Управляющие конструкции и циклы в PHP
Операторы и циклы
PHP предоставляет полный набор управляющих конструкций, позволяющих строить сложную логику выполнения программ. Эти конструкции делятся на две большие группы: условные (ветвление) и циклические (повторение). Внутри этих групп реализованы как классические операторы (if, for), так и современные языковые возможности (match, генераторы).
Все управляющие конструкции работают с выражениями, результат которых интерпретируется в логическом контексте. В PHP любое значение может быть преобразовано к булевому типу по правилам неявного приведения: например, 0, '', [], null, false считаются ложными, всё остальное — истинным.
Условные конструкции
Конструкция if
Конструкция if позволяет выполнять блок кода только при истинности заданного условия.
if (<условие>) {
// выполняется, если условие истинно
} elseif (<другое_условие>) {
// выполняется, если предыдущее ложно, а это — истинно
} else {
// выполняется, если все условия ложны
}
<?php
$temperature = 22;
if ($temperature > 30) {
echo "Жарко";
} elseif ($temperature > 20) {
echo "Комфортно";
} elseif ($temperature > 10) {
echo "Прохладно";
} else {
echo "Холодно";
}
Конструкция поддерживает неограниченное количество веток elseif. Проверка условий происходит строго сверху вниз. Первое истинное условие определяет выполняемый блок; остальные игнорируются.
При работе с внешними данными (например, из $_GET) рекомендуется использовать строгую проверку:
$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
if ($id !== false && $id > 0) {
loadItem($id);
}
Это предотвращает ошибки, связанные с неявным приведением типов.
Альтернативный синтаксис шаблонов
В HTML-шаблонах допустим альтернативный синтаксис, повышающий читаемость:
<?php if (<условие>): ?>
<!-- HTML -->
<?php elseif (<условие>): ?>
<!-- другой HTML -->
<?php else: ?>
<!-- резервный HTML -->
<?php endif; ?>
<?php if ($isLoggedIn): ?>
<div>Привет, <?= htmlspecialchars($user) ?>!</div>
<?php else: ?>
<form method="post" action="/login">
<input name="user">
<button>Войти</button>
</form>
<?php endif; ?>
Этот стиль применяется только в смешанных файлах (HTML + PHP). В чистом коде используется фигурный синтаксис.
Конструкция switch
Конструкция switch сравнивает выражение с набором значений и выполняет соответствующий блок кода.
switch (<выражение>) {
case <значение1>:
// действия
break;
case <значение2>:
// действия
break;
default:
// действия по умолчанию
}
<?php
$status = 404;
switch ($status) {
case 200:
echo "OK";
break;
case 404:
echo "Страница не найдена";
break;
case 500:
echo "Ошибка сервера";
break;
default:
echo "Неизвестный статус";
}
Особенности switch:
- Использует слабое сравнение (
==). Это означает, что'2' == 2—true. - Требует явного указания
breakв конце каждой ветки. Без него выполнение «проваливается» в следующую ветку. - Поддерживает ветку
defaultдля обработки всех остальных случаев. - Может содержать составные инструкции: переменные, циклы, вызовы функций.
Пример проваливания:
switch ($role) {
case 'admin':
grantFullAccess();
// нет break — продолжаем
case 'editor':
grantEditAccess();
break;
default:
grantReadAccess();
}
Такой паттерн допустим, но требует комментариев.
Оператор match (PHP 8.0+)
Оператор match — функциональная альтернатива switch. Он всегда возвращает значение, использует строгое сравнение (===) и не допускает проваливания.
$<результат> = match (<выражение>) {
<значение1> => <результат1>,
<значение2>, <значение3> => <результат2>,
default => <резервный_результат>
};
<?php
$role = 'editor';
$label = match($role) {
'admin' => 'Администратор',
'editor' => 'Редактор',
'user' => 'Пользователь',
default => 'Гость'
};
// Сравнение нескольких значений
$message = match($code) {
200, 201, 204 => 'Успех',
400, 404 => 'Ошибка клиента',
default => 'Неизвестно'
};
Преимущества match:
- Компактность и безопасность.
- Возможность использования внутри выражений.
- Гарантированное покрытие всех случаев (иначе — исключение
UnhandledMatchError).
Ограничения:
- Каждая ветка — одно выражение, без составных инструкций.
- Не подходит для побочных эффектов (например, логирования).
Логические и тернарные операторы
Тернарный оператор
Тернарный оператор позволяет компактно записать простое условное присваивание.
$<результат> = <условие> ? <значение_если_истина> : <значение_если_ложь>;
$status = ($age >= 18) ? 'взрослый' : 'несовершеннолетний';
Сокращённая форма (Elvis operator):
$<результат> = <выражение> ?: <значение_по_умолчанию>;
$username = $_GET['user'] ?: 'Гость';
Здесь $username получит значение $_GET['user'], если оно истинно, иначе — 'Гость'.
Оператор null coalescing (??)
Оператор ?? проверяет значение на строгое равенство null.
$<результат> = $<возможно_null> ?? <значение_по_умолчанию>;
$page = $_GET['page'] ?? 1;
Если $_GET['page'] равно null, будет использовано 1. Значения 0, '0', '' считаются валидными и не заменяются.
Цепочка:
$value = $a ?? $b ?? $c ?? 'default';
Null coalescing assignment (??=)
Начиная с PHP 7.4:
$config['timeout'] ??= 30;
Эквивалентно:
$config['timeout'] = $config['timeout'] ?? 30;
Циклические конструкции
Цикл for
Цикл for используется, когда известно количество итераций или требуется числовая индексация.
for ($<счётчик> = <начало>; $<счётчик> < <конец>; $<счётчик>++) {
// тело цикла
}
for ($i = 0; $i < 5; $i++) {
echo "Итерация $i\n";
}
Компоненты:
- Инициализация — один раз перед циклом.
- Условие — проверяется перед каждой итерацией.
- Инкремент — выполняется после каждой итерации.
Переменная цикла остаётся в области видимости после завершения.
Цикл while
Цикл while проверяет условие перед каждой итерацией.
while (<условие>) {
// тело цикла
}
$count = 3;
while ($count > 0) {
echo "Осталось: $count\n";
$count--;
}
Если условие изначально ложно, тело не выполняется ни разу.
Цикл do-while
Цикл do-while гарантирует выполнение тела хотя бы один раз.
do {
// тело цикла
} while (<условие>);
$input = '';
do {
$input = readline('Введите число от 1 до 10: ');
$number = (int)$input;
} while ($number < 1 || $number > 10);
Обязательна точка с запятой после while.
Цикл foreach
Цикл foreach предназначен для итерации по массивам и объектам.
По значениям:
foreach ($<массив> as $<элемент>) {
// обработка элемента
}
По ключам и значениям:
foreach ($<массив> as $<ключ> => $<значение>) {
// обработка пары
}
$scores = ['Анна' => 95, 'Борис' => 87];
foreach ($scores as $name => $score) {
echo "$name: $score\n";
}
Модификация через ссылку:
foreach ($<массив> as &$<элемент>) {
$<элемент> = <новое_значение>;
}
unset($<элемент>); // обязательный сброс ссылки
$prices = [100, 200];
foreach ($prices as &$price) {
$price *= 1.1;
}
unset($price);
Управление потоком выполнения
Операторы break и continue
Оператор break прекращает выполнение цикла.
Оператор continue переходит к следующей итерации.
Оба принимают необязательный числовой аргумент — количество уровней вложенности для выхода/пропуска:
for ($i = 0; $i < 3; $i++) {
for ($j = 0; $j < 3; $j++) {
if ($i === 1 && $j === 1) {
break 2; // выход из обоих циклов
}
echo "$i,$j ";
}
}
Генераторы и yield
Генераторы позволяют создавать ленивые последовательности без загрузки всех данных в память.
function xrange($start, $end) {
for ($i = $start; $i <= $end; $i++) {
yield $i;
}
}
foreach (xrange(1, 5) as $n) {
echo "$n ";
}
Генератор с ключами:
yield $key => $value;
Генератор можно итерировать только один раз. Для повторного использования вызывается заново.
Рекомендации
- Используйте
===и!==для строгого сравнения. - Предпочитайте
matchвместоswitchпри выборе значения. - Избегайте модификации массива внутри
foreach. - Всегда вызывайте
unset()послеforeach (&$ref). - Валидируйте входные данные до условий.
- Не используйте
and/or— их приоритет ниже ожидаемого.