PHP 8.4.2 Released!

switch

(PHP 4, PHP 5, PHP 7, PHP 8)

Инструкция switch похожа на серию инструкций IF, которые проверяют одно и то же выражение. Одну и ту же переменную или выражение часто сравнивают с разными значениями, чтобы выполнить ту часть кода, условию выполнения которой соответствует значение переменной или выражения. Инструкция switch выполняет такие проверки.

Замечание: Обратите внимание, что в отличие от отдельных языков программирования, действие инструкции continue распространяется на блок switch, а не на отдельный случай, и ведёт себя аналогично инструкции break. При вызове инструкции continue 2 выполнение перейдёт к следующей итерации внешнего цикла, если блок switch выполняет проверки внутри цикла.

Замечание:

Обратите внимание, конструкция switch/case выполняет нестрогое сравнение.

В следующем примере блоки кода выполняют эквивалентные проверки. Один блок выполняет проверки через серию инструкций if и elseif, другой — через инструкцию switch. Каждый блок кода выдаёт одинаковый результат.

Пример #1 Структура инструкции switch

<?php

// Инструкция switch:

switch ($i) {
case
0:
echo
"Значение переменной \$i равно 0";
break;
case
1:
echo
"Значение переменной \$i равно 1";
break;
case
2:
echo
"Значение переменной \$i равно 2";
break;
}

// ...эквивалентна:

if ($i == 0) {
echo
"Значение переменной \$i равно 0";
} elseif (
$i == 1) {
echo
"Значение переменной \$i равно 1";
} elseif (
$i == 2) {
echo
"Значение переменной \$i равно 2";
}

?>

Понимание того, в каком порядке инструкция switch выполняет инструкции случаев, помогает избегать ошибок. Инструкция switch выполняет строку за строкой, или точнее — выражение за выражением. В начале никакой код не выполняется. PHP начинает выполнение инструкции случаев, только когда находит инструкцию case, выражение которой вычисляется как значение, которое совпадает со значением выражения в инструкции switch. Тогда PHP или продолжает выполнять инструкции случаев до конца блока switch, даже если значение случая не совпадает со значением инструкции switch, или пока не увидит первую инструкцию break. PHP продолжит выполнять инструкции следующих случаев, если в конце списка инструкций случая не записали инструкцию break. Приведём пример:

<?php

switch ($i) {
case
0:
echo
"Значение переменной \$i равно 0";
case
1:
echo
"Значение переменной \$i равно 1";
case
2:
echo
"Значение переменной \$i равно 2";
}

?>

PHP выполнит инструкцию echo каждого случая, если значение переменной $i равно 0! PHP выполнит инструкции echo двух последних случаев, если значение переменной $i равно 1. Код поведёт себя предсказуемо и выведет «Значение переменной $i равно 2», только если значение переменной $i равно 2. Поэтому лучше помнить об инструкциях break, даже если в конкретных обстоятельствах инструкции прерывания умышленно не указываются.

В инструкции switch условие вычисляется только один раз, а результат сравнивается со значением выражения каждой инструкции case. В инструкции elseif вычисление условия повторяется. Инструкция switch часто работает быстрее, если условие сложнее простого сравнения «и-или» проверяется в плотном цикле.

Список инструкций в секциях case разрешается оставлять пустым, тогда управление передаётся списку инструкций следующей секции case.

<?php

switch ($i) {
case
0:
case
1:
case
2:
echo
"Значение переменной \$i меньше 3, но не отрицательно";
break;
case
3:
echo
"Значение переменной \$i равно 3";
}

?>

Инструкция default управляет случаями по умолчанию. Управление переходит к случаю по умолчанию при несовпадении значения выражения switch со значениями выражений других случаев. Приведём пример:

<?php

switch ($i) {
case
0:
echo
"Значение переменной \$i равно 0";
break;
case
1:
echo
"Значение переменной \$i равно 1";
break;
case
2:
echo
"Значение переменной \$i равно 2";
break;
default:
echo
"Значение переменной \$i не равно 0, 1 или 2";
}

?>

Замечание: Многократные инструкции default вызовут ошибку уровня E_COMPILE_ERROR.

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

Код не выполнится, как если бы ни одна инструкция if не оказалась истинной, если ни одна ветвь инструкций case не соответствует значению проверки и инструкцию default не указали.

Значение секции case разрешается указывать в виде выражения. Однако это выражение вычисляется само по себе, а затем нестрого сравнивается со значением инструкции switch. Поэтому выражение нельзя использовать для сложных оценок значения конструкции switch. Приведём пример несложной оценки:

<?php

$target
= 1;
$start = 3;

switch (
$target) {
case
$start - 1:
print
"A";
break;
case
$start - 2:
print
"B";
break;
case
$start - 3:
print
"C";
break;
case
$start - 4:
print
"D";
break;
}

// Код выведет "B"

?>

Для более сложных сравнений в значении инструкции switch указывают значение true, или выполняют сравнения альтернативным способом — в блоках if-else.

<?php

$offset
= 1;
$start = 3;

switch (
true) {
case
$start - $offset === 1:
print
"A";
break;
case
$start - $offset === 2:
print
"B";
break;
case
$start - $offset === 3:
print
"C";
break;
case
$start - $offset === 4:
print
"D";
break;
}

// Код выведет "B"

?>

Блоки switch поддерживают альтернативный синтаксис управляющих конструкций. Дополнительную информацию содержит раздел «Альтернативный синтаксис управляющих конструкций».

<?php

switch ($i):
case
0:
echo
"Значение переменной \$i равно 0";
break;
case
1:
echo
"Значение переменной \$i равно 1";
break;
case
2:
echo
"Значение переменной \$i равно 2";
break;
default:
echo
"Значение переменной \$i не равно 0, 1 или 2";
endswitch;

?>

После выражения инструкции case вместо двоеточия разрешается указывать точку с запятой. Например:

<?php

switch ($beer) {
case
'Tuborg';
case
'Carlsberg';
case
'Stella';
case
'Heineken';
echo
'Хороший выбор';
break;
default;
echo
'Пожалуйста, выберите заново...';
break;
}

?>

Смотрите также

Добавить

Примечания пользователей 6 notes

up
289
MaxTheDragon at home dot nl
12 years ago
This is listed in the documentation above, but it's a bit tucked away between the paragraphs. The difference between a series of if statements and the switch statement is that the expression you're comparing with, is evaluated only once in a switch statement. I think this fact needs a little bit more attention, so here's an example:

<?php
$a
= 0;

if(++
$a == 3) echo 3;
elseif(++
$a == 2) echo 2;
elseif(++
$a == 1) echo 1;
else echo
"No match!";

// Outputs: 2

$a = 0;

switch(++
$a) {
case
3: echo 3; break;
case
2: echo 2; break;
case
1: echo 1; break;
default: echo
"No match!"; break;
}

// Outputs: 1
?>

It is therefore perfectly safe to do:

<?php
switch(winNobelPrizeStartingFromBirth()) {
case
"peace": echo "You won the Nobel Peace Prize!"; break;
case
"physics": echo "You won the Nobel Prize in Physics!"; break;
case
"chemistry": echo "You won the Nobel Prize in Chemistry!"; break;
case
"medicine": echo "You won the Nobel Prize in Medicine!"; break;
case
"literature": echo "You won the Nobel Prize in Literature!"; break;
default: echo
"You bought a rusty iron medal from a shady guy who insists it's a Nobel Prize..."; break;
}
?>

without having to worry about the function being re-evaluated for every case. There's no need to preemptively save the result in a variable either.
up
121
septerrianin at mail dot ru
6 years ago
php 7.2.8.
The answer to the eternal question " what is faster?":
1 000 000 000 iterations.

<?php
$s
= time();
for (
$i = 0; $i < 1000000000; ++$i) {
$x = $i%10;
if (
$x == 1) {
$y = $x * 1;
} elseif (
$x == 2) {
$y = $x * 2;
} elseif (
$x == 3) {
$y = $x * 3;
} elseif (
$x == 4) {
$y = $x * 4;
} elseif (
$x == 5) {
$y = $x * 5;
} elseif (
$x == 6) {
$y = $x * 6;
} elseif (
$x == 7) {
$y = $x * 7;
} elseif (
$x == 8) {
$y = $x * 8;
} elseif (
$x == 9) {
$y = $x * 9;
} else {
$y = $x * 10;
}
}
print(
"if: ".(time() - $s)."sec\n");

$s = time();
for (
$i = 0; $i < 1000000000; ++$i) {
$x = $i%10;
switch (
$x) {
case
1:
$y = $x * 1;
break;
case
2:
$y = $x * 2;
break;
case
3:
$y = $x * 3;
break;
case
4:
$y = $x * 4;
break;
case
5:
$y = $x * 5;
break;
case
6:
$y = $x * 6;
break;
case
7:
$y = $x * 7;
break;
case
8:
$y = $x * 8;
break;
case
9:
$y = $x * 9;
break;
default:
$y = $x * 10;
}
}
print(
"switch: ".(time() - $s)."sec\n");
?>

Results:
if: 69sec
switch: 42sec
up
82
nospam at please dot com
24 years ago
Just a trick I have picked up:

If you need to evaluate several variables to find the first one with an actual value, TRUE for instance. You can do it this was.

There is probably a better way but it has worked out well for me.

switch (true) {

case (X != 1):

case (Y != 1):

default:
}
up
6
me at czarpino dot com
2 years ago
Although noted elsewhere, still worth noting is how loose comparison in switch-case was also affected by the change in string to number comparison. Prior PHP8, strings were converted to int before comparison. The reverse is now true which can cause issues for logic that relied on this behavior.

<?php
function testSwitch($key) {
switch (
$key) {
case
'non numeric string':
echo
$key . ' matches "non numeric string"';
break;
}
}

testSwitch(0); // pre-PHP8, returns '0 matches "non numeric string"'
?>
up
1
php at nospam dot k39 dot se
4 months ago
It is possible to prevent nested switch/match/if blocks by checking for multiple cases at once (just beware that PHP uses loose comparison here).

<?php
$a
= "abc";
$b = "def";

switch ([
$a, $b]) {
case [
"abc", "def"]:
$result = 1;
break;
default:
$result = -1;
}
// $result == 1
?>

If for some cases one of the values is not important, you can use the variable itself:

<?php
$a
= "abc";
$b = "def";

switch ([
$a, $b]) {
case [
"xyz", "def"]:
$result = 1;
break;
case [
$a, "def"]:
$result = 2;
break;
default:
$result = -1;
}
// $result == 2
?>
up
4
j dot kane dot third at gmail dot com
2 years ago
The default case appears to always be evaluated last. If break is excluded from the default case, then the proceeding cases will be reevaluated. This behavior appears to be undocumented.

<?php

$kinds
= ['moo', 'kind1', 'kind2'];

foreach (
$kinds as $kind) {
switch(
$kind)
{
default:
// The kind wasn't valid, set it to the default
$kind = 'kind1';
var_dump('default');

case
'kind1':
var_dump('1');
break;

case
'kind2':
var_dump('2');
break;

case
'kindn':
var_dump('n-th');
break;
}

echo
"\n\n";
}

?>
To Top