# Control Flow and match — PHP

Source: https://www.skillbyai.com/en/php/c-flow

> Write conditions and loops and use match instead of switch.

## Branches and loops

PHP has the familiar `if`/`elseif`/`else`, `while`, `do-while`, `for` and **`foreach`**, the main way to iterate arrays and other iterables (`foreach ($orders as $id => $order)`). **`match`** (PHP 8.0) is an expression that returns a value, compares with **strict identity** (`===`), has **no fall-through**, can list several values per arm and throws an `UnhandledMatchError` if nothing matches and there is no `default`. That makes it safer than `switch`, which compares loosely and falls through without `break`. `foreach` by reference (`foreach ($items as &$item)`) modifies the array in place but leaves `$item` referencing the last element afterwards, a classic bug, so `unset($item)` after such loops or avoid references entirely. `break` and `continue` accept a number to exit nested loops (`break 2`). Prefer early returns and small functions over deeply nested conditions.

## match versus switch

match returns a value with strict comparison and no fall-through; switch compares loosely and falls through.

![Two branching diagrams: one with clean separate arrows to outcomes, the other with arrows that spill from one case into the next.](assets/figures/php/section-2-map.svg) — Figure 2.1 — match arms compared with switch cases.

## match, foreach and early returns

match maps statuses to labels with strict comparison.

```php
<?php
declare(strict_types=1);

function statusLabel(string $status): string
{
    return match ($status) {
        'placed', 'paid' => 'In progress',
        'shipped'        => 'On the way',
        'delivered'      => 'Delivered',
        'cancelled'      => 'Cancelled',
        default          => throw new InvalidArgumentException("Unknown status {$status}"),
    };
}

$orders = ['o-1' => 'paid', 'o-2' => 'shipped', 'o-3' => 'cancelled'];

foreach ($orders as $id => $status) {
    if ($status === 'cancelled') {
        continue;                       // skip early
    }
    echo $id, ': ', statusLabel($status), PHP_EOL;
}
```

## Reference loops leave a dangling reference

After `foreach ($rows as &$row)`, `$row` still points at the last element. A later `foreach ($rows as $row)` overwrites that last element on every iteration. Call `unset($row)` right after the reference loop.

**Quiz:** Which is true about match compared with switch?

- [ ] match compares loosely like ==
- [ ] match requires break statements
- [x] match uses strict comparison, returns a value and does not fall through
- [ ] match cannot have a default arm

*Answer:* match uses strict comparison, returns a value and does not fall through. match is a strict, expression-based alternative to switch.
