Перейти к содержимому
Теория · Условия · урок 6 из 8

switch

Часто условие сравнивает одну переменную с длинным списком значений: если день — 6, то «суббота», если 7 — «воскресенье», иначе «будни». Цепочка elseif с этим справится, но в каждом условии придётся повторять $day ===. Для такого выбора в PHP есть switch.

Представьте длинный коридор с дверями. На каждой двери табличка с номером, а у входа стоит вахтёр. Он смотрит на ваш билет, находит первую дверь с подходящим номером и впускает вас. Номер он сверяет нестрого: билет с цифрой 7, написанной от руки, для него то же, что напечатанное число 7.

Давайте посмотрим на switch в деле:

PHP
<?php

$day = 3;
switch ($day) {
    case 6:
        echo 'Saturday', "\n";
        break;
    case 7:
        echo 'Sunday', "\n";
        break;
    default:
        echo 'workday', "\n"; // workday
}

Разберём по частям:

  • switch ($day) — значение, которое будут сравнивать;
  • case 6: — метка, то есть указание «если значение равно 6, начинай отсюда»;
  • break; — выход из switch: дальше выполняется код после закрывающей скобки;
  • default: — метка для всех остальных значений, её можно не писать.

В нашем примере $day равен 3. Ни case 6, ни case 7 не совпали, поэтому PHP выполняет строки после default и печатает workday.

Нестрогое сравнение

switch сравнивает значение с каждой меткой через ==, а не через ===. Поэтому числовая строка, например из формы, попадает в case с числом:

PHP
$input = '7';
switch ($input) {
    case 7:
        echo 'Sunday', "\n"; // Sunday
        break;
    default:
        echo 'unknown', "\n";
}

Строка '7' совпала с числом 7, потому что '7' == 7 истинно: числовую строку == сравнивает как число. А вот нечисловая строка с числом не совпадёт: в PHP 8 'abc' == 0 ложно, и switch ('abc') в case 0 не попадёт.

Проваливание без break

Самое неожиданное в switch начинается после совпадения. Найдя подходящую метку, PHP выполняет все строки подряд до ближайшего break или до конца switch. Следующие метки он при этом не проверяет и проходит насквозь. Такое поведение называют проваливанием.

В нашем коридоре это выглядит так: войдя в свою дверь, вы попадаете в комнату, из которой есть проход в следующую. Вы идёте через комнаты подряд, пока кто-нибудь не скажет «стоп» — break. Нажмите «Следующий шаг» и следите за $kind в рамке {main}: после case 6 PHP не останавливается и дописывает к строке ещё и weekend.

Вживуюswitch без breakшаг 1 из 9 · рамок: 1

В $day лежит 6 — это значение switch будет сравнивать с метками.

Следите, как растёт $kind

Здесь аналогия с коридором перестаёт работать. В настоящем коридоре у каждой двери проверили бы билет снова. switch сверяет метки только до первого совпадения, а дальше идёт насквозь, не глядя на номера.

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

Несколько значений в одном case

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

PHP
$day = 7;
switch ($day) {
    case 6:
    case 7:
        echo 'weekend', "\n"; // weekend
        break;
    default:
        echo 'workday', "\n";
}

$day равен 7, поэтому PHP начинает с метки case 7 и печатает weekend. При 6 он начал бы с пустой метки case 6, провалился в case 7 и дошёл до той же строки.

Частая ошибка

В ветке забыли break:

PHP
$role = 'admin';
switch ($role) {
    case 'admin':
        echo 'full access', "\n"; // ✗
    case 'guest':
        echo 'read only', "\n";
        break;
}

Программа печатает и full access, и read only: после первой ветки break нет, и PHP проваливается в case 'guest'. Сообщения об ошибке не будет, ведь для PHP это допустимый код. Исправление — break; в конце каждой ветки, кроме тех, что проваливаются намеренно.

Главное

  • switch сравнивает значение с каждой меткой case через ==, поэтому строка '7' попадает в case 7.
  • После совпавшей метки PHP выполняет все строки подряд до break, не проверяя следующих меток.
  • default срабатывает, когда не совпала ни одна метка.
  • Забытый break не вызывает ошибки: программа молча выполняет лишние строки.