最好的办法做一个 PHP 切换与多个值的情况下?

你将如何做这个 PHP 开关语句?

还要注意的是,这些是更小的版本,我需要创建的版本将有更多的价值添加到它。

版本一:

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;
}

第二版:

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;
}

测试结果 :

我对一万次迭代进行了速度测试,

时间1:0.0199389457703//If 报表
Time 2:0.0389049446106//switch 语句
时间3:0.106977939606//数组

217204 次浏览

Version 1 is certainly easier on the eyes, clearer as to your intentions, and easier to add case-conditions to.

I've never tried the second version. In many languages, this wouldn't even compile because each case labels has to evaluate to a constant-expression.

I definitely prefer Version 1. Version 2 may require less lines of code, but it will be extremely hard to read once you have a lot of values in there like you're predicting.

(Honestly, I didn't even know Version 2 was legal until now. I've never seen it done that way before.)

If anyone else was ever to maintain your code, they would almost certainly do a double take on version 2 -- that's extremely non-standard.

I would stick with version 1. I'm of the school of though that case statements without a statement block of their own should have an explicit // fall through comment next to them to indicate it is indeed your intent to fall through, thereby removing any ambiguity of whether you were going to handle the cases differently and forgot or something.

Put those many values into an array and query the array, as the switch-case seems to hide the underlying semantics of what you're trying to achieve when a string variable is used as the condition, making it harder to read and understand, e.g.:

$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';
}

I think version 1 is the way to go. It is a lot easier to read and understand.

Version 2 does not work!!

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

is exactly the same as:

case True:

and that case will be chosen for any value of $p, unless $p is the empty string.

|| Does not have any special meaning inside a case statement, you are not comparing $p to each of those strings, you are just checking to see if it's not False.

For any situation where you have an unknown string and you need to figure out which of a bunch of other strings it matches up to, the only solution which doesn't get slower as you add more items is to use an array, but have all the possible strings as keys. So your switch can be replaced with the following:

// 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);

This doesn't look as clean as a switch(), but it is the only fast solution which doesn't include writing a small library of functions and classes to keep it tidy. It is still very easy to add items to the arrays.

No version 2 doesn't actually work but if you want this kind of approach you can do the following (probably not the speediest, but arguably more intuitive):

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

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;
}
}

For the sake of completeness, I'll point out that the broken "Version 2" logic can be replaced with a switch statement that works, and also make use of arrays for both speed and clarity, like so:

// 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);
}

Switch in combination with variable variables will give you more flexibility:

<?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;
?>

To learn more, checkout variable variables and the examples I submitted to php manual:
Example 1: http://www.php.net/manual/en/language.variables.variable.php#105293
Example 2: http://www.php.net/manual/en/language.variables.variable.php#105282

PS: This example code is SMALL AND SIMPLE, just the way I like it. It's tested and works too

Some other ideas not mentioned yet:

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;
}

Someone will probably complain about readability issues with #2, but I would have no problem inheriting code like that.

Nowadays you can do...

switch ([$group1, $group2]){
case ["users", "location"]:
case ["users", "online"]:
Ju_le_do_the_thing();
break;
case ["forum", $group2]:
Foo_the_bar();
break;
}

Here's a ready ready-to-run set of code demonstrating the concept:

<?php


function show_off_array_switch(){
$first_array = ["users", "forum", "StubbornSoda"];
$second_array = ["location", "online", "DownWithPepsiAndCoke"];


$rand1 = array_rand($first_array);
$rand2 = array_rand($second_array);


$group1 = $first_array[$rand1];
$group2 = $second_array[$rand2];


switch ([$group1, $group2]){
case ["users", "location"]:
case ["users", "online"]:
echo "Users and Online";
break;
case ["forum", $group2]:
echo "Forum and variable";
break;
default:
echo "default";
}
echo "\nThe above result was generated using the array: \n" . print_r([$group1, $group2], true);
}


for ($i = 0; $i < 10; $i++){
show_off_array_switch();
}

The following has (for one random run) output the following:

 Users and Online
The above result was generated using the array:
Array
(
[0] => users
[1] => online
)
Users and Online
The above result was generated using the array:
Array
(
[0] => users
[1] => online
)
default
The above result was generated using the array:
Array
(
[0] => users
[1] => DownWithPepsiAndCoke
)
Users and Online
The above result was generated using the array:
Array
(
[0] => users
[1] => location
)
Forum and variable
The above result was generated using the array:
Array
(
[0] => forum
[1] => DownWithPepsiAndCoke
)
Forum and variable
The above result was generated using the array:
Array
(
[0] => forum
[1] => DownWithPepsiAndCoke
)
Forum and variable
The above result was generated using the array:
Array
(
[0] => forum
[1] => online
)
default
The above result was generated using the array:
Array
(
[0] => StubbornSoda
[1] => location
)
Users and Online
The above result was generated using the array:
Array
(
[0] => users
[1] => location
)
Users and Online
The above result was generated using the array:
Array
(
[0] => users
[1] => location
)

maybe

        switch ($variable) {
case 0:
exit;
break;
case (1 || 3 || 4 || 5 || 6):
die(var_dump('expression'));
default:
die(var_dump('default'));
# code...
break;
}

You are simply looking for common patterns in strings. I would have thought a regular expression would be a more efficient way of doing this as PHP implements this with preg_match so little code to write and probably massively quicker. For example:

case preg_match('/^users./'):
// do something here
break;

From PHP documentation you can do that: https://www.php.net/manual/en/control-structures.switch.php#41767

$input = 'users.online';
$checked = null;
        

switch (true):
case ($input === 'home'):
$checked = 'ok 1';
break;


case (in_array($input , ['users.online', 'users.location', 'users.featured', 'users.browse', 'users.search', 'users.staff'])):
$checked = 'ok 2';
break;


case ($input === 'forum'):
$checked = 'ok 3';
break;
endswitch;


echo $checked;

Another option would be Version 2:

if (in_array($p,['users.online','users.location','users.featured','users.browse','users.search','users.staff'])){
$p="users";
}
switch ($p) {
case 'home':
$current_home = 'current';
break;
case 'users':
$current_users = 'current';
break;
case 'forum':
$current_forum = 'current';
break;
}