switch i match — wiele opcji bez chaosu

🎯 Po tej lekcji wybierzesz jedną z wielu opcji czytelnie, używając switch lub match.

Kiedy Kuba pisze program sprawdzający dzień tygodnia, może użyć długiego łańcucha elseif. Ale gdy opcji jest wiele, kod robi się nieczytelny. Z pomocą przychodzą switch i nowoczesny match.

switch — klasyczne rozgałęzienie

switch porównuje jedną zmienną z wieloma możliwymi wartościami:

<?php
declare(strict_types=1);

$dzien = 'poniedziałek';

switch ($dzien) {
    case 'sobota':
    case 'niedziela':
        echo 'Weekend — odpoczywaj!';
        break;
    case 'poniedziałek':
        echo 'Początek tygodnia.';
        break;
    default:
        echo 'Dzień roboczy.';
        break;
}
// wynik: Początek tygodnia.

Kilka ważnych zasad switch:

  • Porównanie jest luźne (==), więc switch(0) dopasuje case false.
  • Po każdym case musisz napisać break, inaczej PHP "wpadnie" do kolejnego case (tzw. fall-through).
  • default wykona się, gdy żaden case nie pasuje.
⚠️ Pułapka fall-through: Jeśli zapomnisz break, PHP wykona też następny case — nawet jeśli jego warunek nie pasuje. To częste źródło błędów.

match — nowoczesna alternatywa (PHP 8.0+)

match rozwiązuje problemy switch w elegancki sposób:

<?php
declare(strict_types=1);

$dzien = 3;

$nazwa = match($dzien) {
    1 => 'poniedziałek',
    2 => 'wtorek',
    3 => 'środa',
    4 => 'czwartek',
    5 => 'piątek',
    6 => 'sobota',
    7 => 'niedziela',
};

echo 'Dzień tygodnia: ' . $nazwa;
// wynik: Dzień tygodnia: środa
💡 Trzy kluczowe różnice match vs switch:
1. Ścisłe porównanie === — typ musi się zgadzać (np. 1 nie pasuje do '1').
2. Zwraca wartośćmatch to wyrażenie, które możesz przypisać do zmiennej.
3. Brak break — każde ramię automatycznie kończy działanie; nie ma fall-through.

UnhandledMatchError — match jest rygorystyczny

Gdy żadne ramię nie pasuje i nie ma default, PHP rzuca wyjątek \UnhandledMatchError:

<?php
declare(strict_types=1);

$status = 99;

// To rzuci wyjątek \UnhandledMatchError!
$opis = match($status) {
    1 => 'aktywny',
    0 => 'nieaktywny',
    // brak default — błąd jeśli $status nie jest 0 ani 1
};

Dlatego zawsze dodawaj default albo miej pewność, że wszystkie możliwe wartości są obsłużone:

<?php
declare(strict_types=1);

$status = 99;

$opis = match($status) {
    1       => 'aktywny',
    0       => 'nieaktywny',
    default => 'nieznany status',
};

echo $opis;
// wynik: nieznany status

Wiele wartości w jednym ramieniu

match pozwala podać kilka wartości w jednym ramieniu, oddzielonych przecinkiem:

<?php
declare(strict_types=1);

$dzien = 6;

$typ = match($dzien) {
    1, 2, 3, 4, 5 => 'dzień roboczy',
    6, 7           => 'weekend',
    default        => throw new \InvalidArgumentException('Nieznany dzień'),
};

echo $typ;
// wynik: weekend

Zauważ, że w default możesz rzucić wyjątek — throw w PHP 8 jest wyrażeniem.

Kiedy używać switch, a kiedy match?

| | switch | match | |---|----------|---------| | Porównanie | luźne == | ścisłe === | | Zwraca wartość | nie | tak | | Wymaga break | tak | nie | | Fall-through | możliwy | niemożliwy | | Brak dopasowania | nic się nie dzieje | \UnhandledMatchError | | Styl | PHP < 8 | PHP 8+ ✓ |

W nowych projektach z PHP 8 używaj match — jest bezpieczniejszy i czytelniejszy.

Sprawdź się

Jaki operator porównania stosuje match?

Co się stanie, jeśli żadne ramię match nie pasuje i nie ma ramienia default?

Czy w match trzeba używać break?

Ćwiczenie

Napisz skrypt z zmienną $dzien (liczba 1–7, gdzie 1 = poniedziałek). Używając match, przypisz do zmiennej $typ wartość 'dzień roboczy' dla dni 1–5 lub 'weekend' dla dni 6–7. Wyświetl wynik.

Pokaż rozwiązanie
<?php
declare(strict_types=1);

$dzien = 6;

$typ = match(true) {
    $dzien >= 1 && $dzien <= 5 => 'dzień roboczy',
    $dzien === 6 || $dzien === 7 => 'weekend',
    default                      => throw new \InvalidArgumentException('Nieznany dzień'),
};

echo 'Dzień ' . $dzien . ' to: ' . $typ;
// wynik: Dzień 6 to: weekend