Лучший способ сделать PHP-коммутатор с несколькими значениями в каждом случае?


Как бы вы сделали этот оператор PHP switch?

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

Вариант 1:

switch ($p) { 
    case 'home': 
    case '': 
        $current_home = 'current';
    break; 

    case 'users.online': 
    case 'users.location': 
    case 'users.featured': 
    case 'users.new': 
    case 'users.browse': 
    case 'users.search': 
    case 'users.staff': 
        $current_users = 'current';
    break;

    case 'forum': 
        $current_forum = 'current';
    break; 
} 

Вариант 2:

switch ($p) { 
    case 'home': 
        $current_home = 'current';
    break; 

    case 'users.online' || 'users.location' || 'users.featured' || 'users.browse' || 'users.search' || 'users.staff': 
        $current_users = 'current';
    break;

    case 'forum': 
        $current_forum = 'current';
    break; 
} 

обновление-результаты теста

Я провел тест скорости на 10 000 итераций,

Time1: 0.0199389457703 / / если заявления
Time2: 0.0389049446106 / / переключатель заявления
Time3: 0.106977939606 // Массивы

12 62

12 ответов:

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

// used for $current_home = 'current';
$group1 = array(
        'home'  => True,
        );

// used for $current_users = 'current';
$group2 = array(
        'users.online'      => True,
        'users.location'    => True,
        'users.featured'    => True,
        'users.new'         => True,
        'users.browse'      => True,
        'users.search'      => True,
        'users.staff'       => True,
        );

// used for $current_forum = 'current';
$group3 = array(
        'forum'     => True,
        );

if(isset($group1[$p]))
    $current_home = 'current';
else if(isset($group2[$p]))
    $current_users = 'current';
else if(isset($group3[$p]))
    $current_forum = 'current';
else
    user_error("$p is invalid", E_USER_ERROR);

это не выглядит так чисто, как switch(), но это только быстро решение, которое не включает в себя написание небольшого библиотека функций и классов, чтобы держать его в порядке. По-прежнему очень легко добавлять элементы в массивы.

Версия 2 не работает!!

case 'users.online' || 'users.location' || ...

точно так же, как:

case True:

и case будет выбран для любого значения $p, Если $p - пустая строка.

|| не имеет никакого особого значения внутри case заявление, вы не сравниваете $p для каждой из этих строк, вы просто проверяете, чтобы увидеть, если это не False.

поместите эти многие значения в массив и запросите массив, так как switch-case, похоже, скрывает основную семантику того, что вы пытаетесь достичь, когда строковая переменная используется в качестве условия, что затрудняет чтение и понимание, например:

$current_home = null;
$current_users = null;
$current_forum = null;

$lotsOfStrings = array('users.online', 'users.location', 'users.featured', 'users.new');

if(empty($p)) {
    $current_home = 'current';
}

if(in_array($p,$lotsOfStrings)) {
    $current_users = 'current';
}

if(0 === strcmp('forum',$p)) {
    $current_forum = 'current';
}

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

Я бы придерживался версии 1. Я из школы, хотя в этом случае утверждения без собственного блока утверждений должны иметь явное // fall through комментарий рядом с ними, чтобы указать, что это действительно ваше намерение провалиться, тем самым устраняя любую двусмысленность того, собираетесь ли вы обрабатывать дела по-другому и забыл, что ли.

для полноты я укажу, что сломанная логика "версии 2" может быть заменена оператором switch, который работает, и и используйте массивы для скорости и ясности, например:

// used for $current_home = 'current';
$home_group = array(
    'home'  => True,
);

// used for $current_users = 'current';
$user_group = array(
    'users.online'      => True,
    'users.location'    => True,
    'users.featured'    => True,
    'users.new'         => True,
    'users.browse'      => True,
    'users.search'      => True,
    'users.staff'       => True,
);

// used for $current_forum = 'current';
$forum_group = array(
    'forum'     => True,
);

switch (true) {
    case isset($home_group[$p]):
        $current_home = 'current';
        break;
    case isset($user_group[$p]):
        $current_users = 'current';
        break;
    case isset($forum_group[$p]):
        $current_forum = 'current';
        break;
    default:
        user_error("$p is invalid", E_USER_ERROR);
}    

Версия 1, безусловно, легче на глазах, яснее о ваших намерениях,и легче добавить case-условия.

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

некоторые другие идеи еще не упомянул:

switch(true){ 
  case in_array($p, array('home', '')): 
    $current_home = 'current'; break;

  case preg_match('/^users\.(online|location|featured|new|browse|search|staff)$/', $p):
    $current_users = 'current'; break;

  case 'forum' == $p:
    $current_forum = 'current'; break; 
}

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

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

(честно говоря, я даже не знал, что версия 2 была права до сих пор. Я никогда не видел, как это делали раньше.)

никакая версия 2 на самом деле не работает, но если вы хотите такой подход, вы можете сделать следующее (вероятно, не самый быстрый, но, возможно, более интуитивный):

switch (true) {
case ($var === 'something' || $var === 'something else'):
// do some stuff
break;
}

Я думаю, что версия 1-это путь. Это намного легче читать и понимать.

if( in_array( $test, $array1 ) )
{
    // do this
}
else if( stristr( $test, 'commonpart' ) )
{
    // do this
}
else
{
    switch( $test )
    {
        case 1:
            // do this
            break;
        case 2:
            // do this
            break;
        default:
            // do this
            break;
    }
}

переключатель в сочетании с переменные даст вам больше гибкости:

<?php
$p = 'home'; //For testing

$p = ( strpos($p, 'users') !== false? 'users': $p);
switch ($p) { 
    default:
        $varContainer = 'current_' . $p; //Stores the variable [$current_"xyORz"] into $varContainer
        ${$varContainer} = 'current'; //Sets the VALUE of [$current_"xyORz"] to 'current'
    break;

}
//For testing
echo $current_home;
?>

чтобы узнать больше, оформить заказ переменные и примеры, которые я представил в руководстве php:
Пример 1: http://www.php.net/manual/en/language.variables.variable.php#105293
Пример 2: http://www.php.net/manual/en/language.variables.variable.php#105282

PS: этот пример кода МАЛЕНЬКИЙ И ПРОСТОЙ, просто так, как мне нравится. Это проверено и работает тоже