EasyТеория5 min

Управляющие структуры

if/else, switch, match, циклы, break/continue

Условные конструкции if/else

<?php
declare(strict_types=1);

$age = 25;

// Basic if
if ($age >= 18) {
    echo 'Adult';
}

// if/else
if ($age >= 18) {
    echo 'Adult';
} else {
    echo 'Minor';
}

// if/elseif/else
if ($age < 13) {
    echo 'Child';
} elseif ($age < 18) {
    echo 'Teenager';
} else {
    echo 'Adult';
}

Альтернативный синтаксис (для шаблонов)

<?php
declare(strict_types=1);

$role = 'admin';
?>

<?php if ($role === 'admin'): ?>
    <div class="admin-panel">Admin Panel</div>
<?php elseif ($role === 'editor'): ?>
    <div class="editor-panel">Editor Panel</div>
<?php else: ?>
    <div class="user-panel">User Panel</div>
<?php endif; ?>

Ловушка экзамена: Обратите внимание: elseif (слитно) и else if (раздельно) работают одинаково с фигурными скобками, но в альтернативном синтаксисе (с двоеточием) можно использовать ТОЛЬКО elseif слитно! else if: вызовет ошибку.

<?php
declare(strict_types=1);

$x = 5;

// This is VALID:
if ($x > 0):
    echo 'Positive';
elseif ($x < 0):  // OK — one word
    echo 'Negative';
endif;

// This is INVALID in colon syntax:
// if ($x > 0):
//     echo 'Positive';
// else if ($x < 0):  // PARSE ERROR — two words!
//     echo 'Negative';
// endif;

Тернарный оператор

<?php
declare(strict_types=1);

$age = 20;

// Classic ternary
$status = ($age >= 18) ? 'adult' : 'minor';

// Short ternary (Elvis operator) — PHP 5.3+
$name = '' ?: 'Anonymous';     // 'Anonymous' (empty string is falsy)
$name = 'Alice' ?: 'Anonymous'; // 'Alice'

// Ternary is LEFT-associative in PHP (unlike most languages)
// This is DEPRECATED since PHP 7.4, ERROR in PHP 8.0+
// $value = true ? 'a' : true ? 'b' : 'c';
// Use explicit parentheses:
$value = true ? 'a' : (true ? 'b' : 'c');

Ловушка экзамена: Вложенный тернарный оператор без скобок запрещён с PHP 8.0 (deprecated с 7.4). В PHP 7 $a ? 'x' : $b ? 'y' : 'z' интерпретируется как ($a ? 'x' : $b) ? 'y' : 'z' — левоассоциативно, что отличается от большинства языков!

Switch

<?php
declare(strict_types=1);

$color = 'red';

switch ($color) {
    case 'red':
        echo 'Red color';
        break;
    case 'blue':
    case 'navy':  // Fall-through: both match
        echo 'Blue shade';
        break;
    case 'green':
        echo 'Green color';
        break;
    default:
        echo 'Unknown color';
        break;
}

Подводные камни switch

<?php
declare(strict_types=1);

// Switch uses LOOSE comparison (==), not strict (===)!
$value = 0;

switch ($value) {
    case 'hello':
        echo 'Matched hello!';  // In PHP 7 this WOULD match!
        break;                   // In PHP 8.0+ it does NOT (changed == behavior)
    case 0:
        echo 'Matched 0';
        break;
}

// Forgetting break — fall-through!
$num = 1;
switch ($num) {
    case 1:
        echo 'One ';
        // Missing break!
    case 2:
        echo 'Two ';
        // Missing break!
    case 3:
        echo 'Three';
        break;
}
// Output: "One Two Three" — all cases execute!

Ловушка экзамена: switch использует нестрогое сравнение (==). Это означает, что case 0: может совпасть со строкой '' (пустой). Если нужно строгое сравнение — используйте match (PHP 8.0+).

Match (PHP 8.0+)

<?php
declare(strict_types=1);

$status = 200;

// match uses STRICT comparison (===)
$text = match ($status) {
    200 => 'OK',
    301 => 'Moved Permanently',
    404 => 'Not Found',
    500, 503 => 'Server Error',  // Multiple values
    default => 'Unknown',
};

echo $text; // 'OK'

Отличия match от switch

Особенность switch match
Сравнение == (нестрогое) === (строгое)
Возврат значения Нет (statement) Да (expression)
break нужен? Да Нет
Fall-through Да (без break) Нет
Несовпадение Продолжает работу UnhandledMatchError
Множественные условия Несколько case Через запятую
<?php
declare(strict_types=1);

// match is an EXPRESSION (returns a value)
$result = match (true) {
    $age < 13  => 'child',
    $age < 18  => 'teenager',
    $age < 65  => 'adult',
    default    => 'senior',
};

// No match without default = UnhandledMatchError!
$value = 'unknown';
// $result = match ($value) {
//     'a' => 1,
//     'b' => 2,
// };
// UnhandledMatchError: Unhandled match case "unknown"

// match with no argument (match(true))
$temp = 35;
$feeling = match (true) {
    $temp < 0   => 'freezing',
    $temp < 15  => 'cold',
    $temp < 25  => 'comfortable',
    $temp < 35  => 'warm',
    default     => 'hot',
};

Запомни: match — это выражение (expression), а switch — инструкция (statement). match можно присвоить переменной, передать в функцию и т.д. При отсутствии совпадения без default — выбрасывается UnhandledMatchError.

Циклы

while

<?php
declare(strict_types=1);

$i = 0;
while ($i < 5) {
    echo $i . ' ';  // 0 1 2 3 4
    $i++;
}

do-while

<?php
declare(strict_types=1);

// Body executes AT LEAST once
$i = 10;
do {
    echo $i . ' ';  // 10 — executes once even though condition is false
    $i++;
} while ($i < 5);

Ловушка экзамена: do-while ВСЕГДА выполняет тело хотя бы один раз, даже если условие изначально ложно. В примере выше тело выполнится один раз и выведет 10.

for

<?php
declare(strict_types=1);

// Classic for loop
for ($i = 0; $i < 5; $i++) {
    echo $i . ' ';  // 0 1 2 3 4
}

// Multiple expressions
for ($i = 0, $j = 10; $i < $j; $i++, $j--) {
    echo "($i, $j) ";  // (0,10) (1,9) (2,8) (3,7) (4,6)
}

// Infinite loop
// for (;;) {
//     // Must break manually
// }

// Performance: calculate count outside the loop!
$items = range(1, 100);

// BAD: count() called on every iteration
for ($i = 0; $i < count($items); $i++) { /* ... */ }

// GOOD: count() called once
$count = count($items);
for ($i = 0; $i < $count; $i++) { /* ... */ }

// ALSO GOOD:
for ($i = 0, $count = count($items); $i < $count; $i++) { /* ... */ }

foreach

<?php
declare(strict_types=1);

$fruits = ['apple', 'banana', 'cherry'];

// Value only
foreach ($fruits as $fruit) {
    echo $fruit . ' ';
}

// Key and value
foreach ($fruits as $index => $fruit) {
    echo "$index: $fruit\n";
}

// Modifying values by reference
$numbers = [1, 2, 3, 4, 5];
foreach ($numbers as &$num) {
    $num *= 2;
}
unset($num);  // CRITICAL: unset reference after loop!
// $numbers is now [2, 4, 6, 8, 10]

Ловушка экзамена: После foreach с ссылкой (&$var) ОБЯЗАТЕЛЬНО вызовите unset($var)! Без этого переменная $var остаётся ссылкой на последний элемент массива, и дальнейшее использование $var может непредсказуемо изменить массив.

<?php
declare(strict_types=1);

$arr = [1, 2, 3];

foreach ($arr as &$val) {
    // $val is a reference to each element
}
// $val still references $arr[2]!

foreach ($arr as $val) {
    // Each iteration overwrites $arr[2] via the reference!
}
// $arr is now [1, 2, 2] — NOT [1, 2, 3]!

// Fix: always unset after reference foreach
$arr = [1, 2, 3];
foreach ($arr as &$val) {
    $val *= 10;
}
unset($val);  // Properly break the reference
// $arr is now [10, 20, 30]

Деструктуризация в foreach

<?php
declare(strict_types=1);

$users = [
    ['Alice', 25],
    ['Bob', 30],
    ['Charlie', 35],
];

// Array destructuring (PHP 7.1+)
foreach ($users as [$name, $age]) {
    echo "$name is $age years old\n";
}

// With keys
$data = [
    ['name' => 'Alice', 'age' => 25],
    ['name' => 'Bob', 'age' => 30],
];

foreach ($data as ['name' => $name, 'age' => $age]) {
    echo "$name: $age\n";
}

break и continue

<?php
declare(strict_types=1);

// break exits the loop
for ($i = 0; $i < 10; $i++) {
    if ($i === 5) {
        break;
    }
    echo $i . ' ';  // 0 1 2 3 4
}

// continue skips to the next iteration
for ($i = 0; $i < 10; $i++) {
    if ($i % 2 === 0) {
        continue;
    }
    echo $i . ' ';  // 1 3 5 7 9
}

// break/continue with depth (nested loops)
for ($i = 0; $i < 3; $i++) {
    for ($j = 0; $j < 3; $j++) {
        if ($j === 1) {
            continue 2;  // Continue OUTER loop
        }
        echo "($i,$j) ";
    }
}
// Output: (0,0) (1,0) (2,0)

// break 2 exits both loops
for ($i = 0; $i < 3; $i++) {
    for ($j = 0; $j < 3; $j++) {
        if ($i === 1 && $j === 1) {
            break 2;  // Exit BOTH loops
        }
        echo "($i,$j) ";
    }
}
// Output: (0,0) (0,1) (0,2) (1,0)

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

goto

<?php
declare(strict_types=1);

// goto exists but is STRONGLY discouraged
goto end;

echo 'This is skipped';

end:
echo 'This is printed';

// Limitations:
// - Cannot jump INTO a loop or switch
// - Cannot jump out of a function
// - Can only jump within the same file/scope

Ловушка экзамена: goto существует в PHP, но НЕЛЬЗЯ прыгнуть внутрь цикла, switch или функции. Можно только прыгнуть вперёд или назад в пределах одной области видимости. На экзамене могут спросить про ограничения goto.

Альтернативный синтаксис

<?php
declare(strict_types=1);

$items = ['a', 'b', 'c'];
$show = true;
?>

<!-- Alternative syntax for templates -->
<?php if ($show): ?>
    <ul>
    <?php foreach ($items as $item): ?>
        <li><?= htmlspecialchars($item) ?></li>
    <?php endforeach; ?>
    </ul>
<?php endif; ?>

<?php
// Available alternative syntax:
// if/endif
// while/endwhile
// for/endfor
// foreach/endforeach
// switch/endswitch

// NOT available for:
// do-while (no alternative syntax!)
// match (no alternative syntax!)

Вопросы с экзамена ZCE

Проверь себя

5 из 24

Каким будет вывод следующего PHP-скрипта? ```php for ($i = 0; $i < 3; $i++) { for ($j = 3; $j > 0; $j--) { if ($i == $j) { break; } echo $j; } } ```

Разработчик написал следующий код: Каким будет вывод скрипта? ```php switch(1) { case 1: print("Book Details"); case 2: print("Book Author"); default: print("Missing Book"); } ```

Каким будет вывод следующего кода? ```php function print_conditional() { static $x; if ($x++ == 1) echo "many"; echo "good"; echo "things"; return $x; } $x = 1; print_conditional(); $x++; print_conditional(); ```

Дан массив: Вы хотите перебрать этот массив и изменить значение каждого элемента. Какой цикл лучше всего подходит для этой задачи? ```php $somearray = ["hi", "this is a string", "this is a code"]; ```

Какой тип сравнения использует `match`?

Code Challenges

Числа Фибоначчи

Напишите функцию, которая возвращает N-е число Фибоначчи (0-индексированное: F(0)=0, F(1)=1).

Test Cases

1. Input: 0→ Expected: 0
2. Input: 1→ Expected: 1
3. Input: 6→ Expected: 8
4. Input: 10→ Expected: 55