Это плохая картина? (Переключение внутри цикла for / foreach) - PullRequest
7 голосов
/ 31 октября 2009

Я пишу такой код, как:

foreach($array as $key => $value) {
    switch($key) {
        case 'something':
            doSomething($value);
            break;
        case 'somethingelse':
            doSomethingElse($value);
            break;
    }
}

Есть ли лучший способ сделать это? Мне это кажется грязным, но я могу просто подумать об этом.

Единственная альтернатива, о которой я могу подумать, - это оператор if для каждого ключа, который не выглядит лучше. То есть :

if($array[0] == 'something') {
    doSomething($array[0]);
}
if($array[1] == 'somethingelse') {
    doSomethingElse($array[1]);
}

(или что-то в этом роде)

Я могу опубликовать точный код, если это необходимо, но это общее описание того, что происходит. Пожалуйста, критикуйте прочь, но помните, что я ищу здесь помощь. Так что, если я делаю что-то ужасно неправильное, укажите на это.

Ответы [ 6 ]

15 голосов
/ 31 октября 2009

Отображение ваших функций на клавиши в словаре / ассоциативном массиве является распространенным подходом для этой ситуации (как упоминал @jldupont) - не только в PHP, но и во многих динамических языках с ассоциативными массивами. Например, у Python и Lua даже нет оператора switch - это практически единственный способ эмулировать switch.

Рассмотрим этот подход:

<?
$arr[] = "bye";
$arr[] = "hi";

function sayHi() { print("Hello.\n"); }
function sayBye() { print("Goodbye.\n"); }

$funcs["hi"] = sayHi;
$funcs["bye"] = sayBye;

foreach($arr as $k){
    $funcs[$k]();
}

?>

Выход:

Goodbye.
Hello.

Когда у вас есть только два разных значения, это излишне, но, очевидно, это становится более целесообразным подходом, поскольку число ситуаций, которые вы должны охватить, увеличивается.

5 голосов
/ 31 октября 2009

Это не «плохое» решение, но, как всегда, есть альтернативы. Например, вы можете избавиться от оператора switch и использовать интерпретируемый обработчик для строк. Это похоже на список указателей функций, но вам не нужно обновлять список, чтобы добавить новое поведение; простое добавление новой функции в обработчик позаботится об этом.

$array = array(
  "something" => "itsasecret",
  "somethingelse" => "i can't tell you",
);

class Handler {
  static function something($value) {
    printf("something: %s\n", $value);
  }

  static function somethingelse($value) {
    printf("somethingelse: %s\n", $value);
  }
}

$handler = new Handler();
foreach($array as $key => $value) {
  $handler->$key($value);
}

Вам, вероятно, понадобится некоторый код для очистки входных строк и обеспечения того, что метод существует в вашем обработчике, но это может дать вам некоторые идеи.

4 голосов
/ 31 октября 2009

Я склонен использовать переключатель в цикле foreach. ИМХО менее грязно, чем куча если.

Вы можете поместить свой переключатель в другую функцию, например:

foreach($array as $key => $value) {
   doTransaction($key , $value);
}

...

function doTransaction($key, $value){
     switch($key) {
        case 'something':
            doSomething($value);
            break;
        case 'somethingelse':
            doSomethingElse($value);
           break;
    }
}
1 голос
/ 31 октября 2009

Существует (как минимум) другая возможность: использовать поиск по словарю для отправки работы в функцию.

Поиск функции с использованием $ key в качестве «ключа», получение ссылки на функцию и применение ее с $ value в качестве параметра.

Простите, но мой PHP-фу немного ржавый.

0 голосов
/ 31 октября 2009

В этом нет ничего плохого.

Если у вас есть только 2 или 3 элемента, я бы остановился на них просто ради сложности кода Если у вас больше 5, я бы определенно пошел с выключателем ...

0 голосов
/ 31 октября 2009

Попробуйте это:

Выполните каждую версию - с переключателем и с - миллион раз. Время каждого забега.

Дайте нам знать, какой из них работает быстрее.

...