Lekcja 6: Instrukcje warunkowe (if, else, elseif, switch)

Witaj w szóstej lekcji kursu PHP! Po opanowaniu zmiennych, typów danych oraz operatorów, jesteś gotowy na kolejny fundamentalny element programowania: instrukcje warunkowe. Pozwalają one Twoim skryptom podejmować decyzje i wykonywać różne bloki kodu w zależności od tego, czy określone warunki są spełnione, czy nie. Dzięki nim programy stają się dynamiczne i potrafią reagować na różne sytuacje. W tej lekcji szczegółowo omówimy konstrukcje if, else, elseif oraz switch.

Czym są instrukcje warunkowe?

Instrukcje warunkowe, nazywane również instrukcjami sterującymi przepływem, pozwalają na kierowanie wykonaniem programu. Program nie zawsze wykonuje się liniowo, od góry do dołu. Często musi wybrać jedną z kilku możliwych ścieżek w zależności od aktualnego stanu danych lub interakcji użytkownika. Na przykład, strona internetowa może wyświetlać inny komunikat w zależności od tego, czy użytkownik jest zalogowany, czy nie, lub sklep internetowy może naliczać rabat tylko wtedy, gdy wartość zamówienia przekracza określoną kwotę.

Podstawą działania instrukcji warunkowych jest ewaluacja wyrażenia logicznego (warunku). Jeśli warunek jest prawdziwy (true), wykonywany jest jeden blok kodu. Jeśli jest fałszywy (false), może być wykonany inny blok kodu lub program może przejść dalej, pomijając dany fragment.

Instrukcja if

Najprostszą instrukcją warunkową jest if. Pozwala ona na wykonanie bloku kodu tylko wtedy, gdy określony warunek jest prawdziwy.

Składnia instrukcji if wygląda następująco:

<?php
if (warunek) {
    // Blok kodu do wykonania, jeśli warunek jest true
}
?>

Gdzie warunek to dowolne wyrażenie, które PHP potrafi zinterpretować jako wartość logiczną (bool). Może to być bezpośrednio wartość true lub false, zmienna logiczna, wynik porównania (np. $wiek >= 18) lub wynik operacji logicznej (np. $jestZalogowany && $maUprawnienia).

Jeśli blok kodu wewnątrz instrukcji if zawiera tylko jedną instrukcję, nawiasy klamrowe { } można pominąć. Jednak dla czytelności i uniknięcia błędów przy dodawaniu kolejnych instrukcji, zaleca się zawsze używać nawiasów klamrowych.

<?php
$temperatura = 25;

if ($temperatura > 20) {
    echo "Jest ciepło! Możesz założyć krótkie spodenki.<br>";
    echo "Pamiętaj o nawadnianiu organizmu.<br>";
}

$uzytkownikZalogowany = true;
if ($uzytkownikZalogowany) echo "Witaj zalogowany użytkowniku! (jedna instrukcja)<br>";

// Przykład z wartością, która konwertuje się na false
$liczbaProduktow = 0;
if ($liczbaProduktow) { // 0 konwertuje się na false, więc ten blok się nie wykona
    echo "Masz produkty w koszyku.<br>";
}
?>

W pierwszym przykładzie, ponieważ $temperatura (25) jest większa niż 20, oba komunikaty wewnątrz bloku if zostaną wyświetlone. W trzecim przykładzie, $liczbaProduktow wynosi 0, co w kontekście logicznym jest traktowane jako false, więc komunikat się nie pojawi.

Instrukcja if...else

Często chcemy wykonać jeden blok kodu, gdy warunek jest prawdziwy, a inny blok kodu, gdy warunek jest fałszywy. Do tego służy instrukcja if...else.

Składnia:

<?php
if (warunek) {
    // Blok kodu do wykonania, jeśli warunek jest true
} else {
    // Blok kodu do wykonania, jeśli warunek jest false
}
?>
<?php
$wiek = 17;

if ($wiek >= 18) {
    echo "Jesteś pełnoletni. Możesz głosować.<br>";
} else {
    echo "Jesteś niepełnoletni. Nie możesz jeszcze głosować.<br>";
    $pozostaloLat = 18 - $wiek;
    echo "Do pełnoletności pozostało Ci: $pozostaloLat lat.<br>";
}

$haslo = "secret123";
$wprowadzoneHaslo = "secret1234";

if ($haslo === $wprowadzoneHaslo) {
    echo "Hasło poprawne. Dostęp przyznany.<br>";
} else {
    echo "Błędne hasło. Dostęp zabroniony.<br>";
}
?>

W pierwszym przykładzie, ponieważ $wiek (17) nie jest większy lub równy 18, warunek jest fałszywy, więc wykonany zostanie blok kodu wewnątrz else. W drugim przykładzie, używamy ścisłego porównania === do sprawdzenia hasła. Ponieważ hasła się różnią, wykonany zostanie blok else.

Instrukcja if...elseif...else

Czasami mamy więcej niż dwa możliwe scenariusze. Możemy chcieć sprawdzić kilka warunków po kolei i wykonać odpowiedni blok kodu dla pierwszego spełnionego warunku. Do tego służy konstrukcja if...elseif...else. Słowo kluczowe elseif można również zapisać jako else if (ze spacją) – oba zapisy są poprawne i działają tak samo, choć elseif jest częściej spotykane.

Składnia:

<?php
if (warunek1) {
    // Blok kodu do wykonania, jeśli warunek1 jest true
} elseif (warunek2) {
    // Blok kodu do wykonania, jeśli warunek1 jest false, a warunek2 jest true
} elseif (warunek3) {
    // Blok kodu do wykonania, jeśli warunek1 i warunek2 są false, a warunek3 jest true
} else {
    // Blok kodu do wykonania, jeśli wszystkie powyższe warunki są false
}
?>

Można użyć dowolnej liczby bloków elseif. Blok else na końcu jest opcjonalny – jeśli go nie ma, a żaden z warunków if ani elseif nie jest spełniony, żaden z tych bloków kodu się nie wykona.

<?php
$ocena = 75;

if ($ocena >= 90) {
    echo "Ocena: Bardzo dobry (A)<br>";
} elseif ($ocena >= 80) {
    echo "Ocena: Dobry (B)<br>";
} elseif ($ocena >= 70) {
    echo "Ocena: Dostateczny (C)<br>"; // Ten warunek zostanie spełniony (75 >= 70)
} elseif ($ocena >= 60) {
    echo "Ocena: Dopuszczający (D)<br>";
} else {
    echo "Ocena: Niedostateczny (F)<br>";
}

$dzienTygodnia = "Środa";

if ($dzienTygodnia === "Poniedziałek") {
    echo "Początek tygodnia pracy.<br>";
} elseif ($dzienTygodnia === "Piątek") {
    echo "Już prawie weekend!<br>";
} elseif ($dzienTygodnia === "Sobota" || $dzienTygodnia === "Niedziela") {
    echo "Weekend! Czas na odpoczynek.<br>";
} else {
    echo "Kolejny dzień pracy...<br>"; // Ten blok się wykona dla "Środa"
}
?>

Ważne jest, aby pamiętać, że PHP wykonuje tylko blok kodu odpowiadający pierwszemu spełnionemu warunkowi od góry. Nawet jeśli kolejne warunki elseif również byłyby prawdziwe, nie zostaną one sprawdzone ani wykonane po znalezieniu pierwszego pasującego.

Alternatywna Składnia dla Instrukcji Warunkowych (Przydatna w Szablonach HTML)

PHP oferuje alternatywną składnię dla instrukcji warunkowych (oraz pętli), która może być bardziej czytelna podczas mieszania kodu PHP z HTML. Zamiast nawiasów klamrowych { }, używa się dwukropka : po warunku i odpowiednich słów kluczowych endif;, else:, elseif (...):.

Składnia if:

<?php if (warunek): ?>
    <!-- Kod HTML lub PHP do wykonania, jeśli warunek jest true -->
<?php endif; ?>

Składnia if...else:

<?php if (warunek): ?>
    <!-- Kod HTML lub PHP dla true -->
<?php else: ?>
    <!-- Kod HTML lub PHP dla false -->
<?php endif; ?>

Składnia if...elseif...else:

<?php if (warunek1): ?>
    <!-- Kod dla warunek1 true -->
<?php elseif (warunek2): ?>
    <!-- Kod dla warunek2 true -->
<?php else: ?>
    <!-- Kod dla wszystkich false -->
<?php endif; ?>

Przykład użycia w szablonie HTML:

<?php $uzytkownikZalogowany = true; $nazwaUzytkownika = "Alicja"; ?>

<div class="profil">
    <?php if ($uzytkownikZalogowany): ?>
        <p>Witaj, <strong><?= htmlspecialchars($nazwaUzytkownika) ?></strong>!</p>
        <a href="logout.php">Wyloguj się</a>
    <?php else: ?>
        <p>Jesteś gościem. Proszę się <a href="login.php">zalogować</a> lub <a href="register.php">zarejestrować</a>.</p>
    <?php endif; ?>
</div>

Ta składnia jest często preferowana w plikach szablonów (widokach w architekturze MVC), ponieważ oddziela bloki HTML w bardziej naturalny sposób niż nawiasy klamrowe PHP wplecione w HTML.

Instrukcja switch

Instrukcja switch jest alternatywą dla długiej serii instrukcji if...elseif...else, gdy chcemy porównać jedną zmienną (lub wyrażenie) z wieloma różnymi, konkretnymi wartościami.

Składnia:

<?php
switch (wyrazenie) {
    case wartosc1:
        // Blok kodu do wykonania, jeśli wyrazenie === wartosc1
        break; // Ważne! Przerywa wykonanie switch
    case wartosc2:
        // Blok kodu do wykonania, jeśli wyrazenie === wartosc2
        break;
    case wartosc3:
    case wartosc4: // Można grupować przypadki
        // Blok kodu do wykonania, jeśli wyrazenie === wartosc3 LUB wyrazenie === wartosc4
        break;
    default:
        // Blok kodu do wykonania, jeśli żaden z powyższych przypadków (case) nie pasuje
        // Blok default jest opcjonalny
}
?>

Kluczowe elementy instrukcji switch:

<?php
$kolor = "czerwony";

switch ($kolor) {
    case "czerwony":
        echo "Wybrałeś kolor czerwony.<br>";
        break;
    case "zielony":
        echo "Wybrałeś kolor zielony.<br>";
        break;
    case "niebieski":
        echo "Wybrałeś kolor niebieski.<br>";
        break;
    default:
        echo "Nie znam tego koloru. Dostępne: czerwony, zielony, niebieski.<br>";
}

$dzienTygodniaNumer = date("N"); // 1 (Pon) do 7 (Niedz)

switch ($dzienTygodniaNumer) {
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
        echo "To jest dzień roboczy.<br>";
        break;
    case 6:
    case 7:
        echo "To jest weekend!<br>";
        break;
    default:
        echo "Niepoprawny numer dnia tygodnia.<br>"; // Teoretycznie nie powinno się zdarzyć dla date("N")
}

// Przykład z fall-through (celowe pominięcie break)
$poziomUprawnien = "redaktor";

switch ($poziomUprawnien) {
    case "administrator":
        echo "Ma pełne uprawnienia administratora.<br>";
        // fall-through
    case "redaktor":
        echo "Ma uprawnienia redaktora (może edytować treści).<br>";
        // fall-through
    case "uzytkownik":
        echo "Ma podstawowe uprawnienia użytkownika (może przeglądać).<br>";
        break;
    default:
        echo "Nieznany poziom uprawnień.<br>";
}
// Dla $poziomUprawnien = "redaktor", wyświetli:
// Ma uprawnienia redaktora (może edytować treści).
// Ma podstawowe uprawnienia użytkownika (może przeglądać).

// Porównanie w switch jest luźne (==), ale z pewnymi niuansami.
// Jeśli porównujemy string z liczbą, string jest konwertowany na liczbę.
$i = "0";
switch ($i) {
    case 0:
        echo "i jest 0 (case 0)<br>"; // Ten blok się wykona
        break;
    case "a":
        echo "i jest a (case a)<br>";
        break;
}

// Od PHP 8.0.0, switch zachowuje się bardziej jak ścisłe porównanie, gdy chodzi o konwersję typów
// dla nie-numerycznych stringów. Np. "foo" == 0 jest true, ale w switch "foo" nie dopasuje case 0.
// Jednak dla numerycznych stringów jak "0", "1", "42", nadal zachodzi konwersja.
// Zawsze najlepiej jest używać tego samego typu w wyrażeniu switch i w case'ach.
?>

Instrukcja switch jest szczególnie przydatna, gdy mamy jedną zmienną i wiele możliwych, dyskretnych wartości, z którymi chcemy ją porównać. Dla bardziej złożonych warunków (np. zakresów wartości, wielu różnych zmiennych w warunkach) lepszym wyborem będzie if...elseif...else.

Operator Trójargumentowy (Ternary Operator) jako Skrócony if...else

Jak wspomnieliśmy w lekcji o operatorach, operator trójargumentowy ?: jest zwięzłą formą instrukcji if...else, używaną głównie do przypisywania jednej z dwóch wartości do zmiennej w zależności od warunku.

$zmienna = (warunek) ? wartosc_jesli_prawda : wartosc_jesli_falsz;

<?php
$wiek = 20;
$status = ($wiek >= 18) ? "Pełnoletni" : "Niepełnoletni";
echo "Status: $status<br>"; // Pełnoletni

$liczba = 10;
$parzystosc = ($liczba % 2 == 0) ? "Parzysta" : "Nieparzysta";
echo "Liczba $liczba jest: $parzystosc<br>"; // Parzysta

// Można zagnieżdżać, ale staje się to mniej czytelne (lepiej użyć if/elseif)
$punkty = 75;
$ocenaNapis = ($punkty >= 90) ? "Bardzo dobry" :
              (($punkty >= 70) ? "Dobry" :
              (($punkty >= 50) ? "Dostateczny" : "Niedostateczny"));
echo "Ocena (ternary): $ocenaNapis<br>"; // Dobry
?>

Od PHP 5.3 istnieje również skrócona forma operatora trójargumentowego, tzw. "Elvis operator" ?: (nie mylić z operatorem koalescencji ??). Jeśli pierwsza część jest pominięta, zwraca ona pierwszy operand, jeśli jest on prawdziwy (nie-false), w przeciwnym razie zwraca drugi operand.

$wynik = $wyrazenie1 ?: $wyrazenie2; jest równoważne $wynik = $wyrazenie1 ? $wyrazenie1 : $wyrazenie2;

<?php
$domyslnaNazwa = "Gość";
$podanaNazwa = ""; // Pusty ciąg, który konwertuje się na false
$finalnaNazwa = $podanaNazwa ?: $domyslnaNazwa;
echo "Finalna nazwa (Elvis): $finalnaNazwa<br>"; // Gość

$innaNazwa = "Marek";
$finalnaNazwa2 = $innaNazwa ?: $domyslnaNazwa;
echo "Finalna nazwa 2 (Elvis): $finalnaNazwa2<br>"; // Marek
?>

Jednak operator koalescencji NULL (??) wprowadzony w PHP 7 jest często lepszym wyborem niż "Elvis operator", jeśli chcemy sprawdzić, czy zmienna jest NULL lub nieustawiona, a nie tylko czy jest "fałszywa".

Podsumowanie Lekcji

W tej lekcji nauczyliśmy się, jak używać instrukcji warunkowych w PHP do kontrolowania przepływu wykonania programu. Omówiliśmy podstawową instrukcję if, rozszerzenie jej o blok else do obsługi alternatywnych scenariuszy, oraz konstrukcję if...elseif...else do sprawdzania wielu warunków. Poznaliśmy również alternatywną składnię z dwukropkami, przydatną w szablonach HTML. Następnie przyjrzeliśmy się instrukcji switch jako alternatywie dla wielokrotnych porównań z konkretnymi wartościami, zwracając uwagę na znaczenie instrukcji break. Na koniec przypomnieliśmy sobie o operatorze trójargumentowym jako zwięzłej formie if...else.

Instrukcje warunkowe są sercem logiki w programowaniu, pozwalając aplikacjom na inteligentne reagowanie na dane i zdarzenia. W następnej lekcji zajmiemy się kolejnym kluczowym elementem sterowania przepływem: pętlami (while, do...while, for, foreach), które umożliwiają wielokrotne wykonywanie bloków kodu.


Zadanie praktyczne

Napisz skrypt PHP, który:

  1. Zadeklaruj zmienną $godzina i przypisz jej aktualną godzinę jako liczbę całkowitą (0-23), używając funkcji date("G").
  2. Używając instrukcji if...elseif...else, wyświetl odpowiedni komunikat powitalny w zależności od pory dnia:
    • Jeśli godzina jest między 6 a 11 (włącznie), wyświetl "Dzień dobry!".
    • Jeśli godzina jest między 12 a 17 (włącznie), wyświetl "Miłego popołudnia!".
    • Jeśli godzina jest między 18 a 21 (włącznie), wyświetl "Dobry wieczór!".
    • W pozostałych przypadkach (noc), wyświetl "Dobrej nocy!".
  3. Zadeklaruj zmienną $ulubionyOwoc i przypisz jej nazwę owocu (np. "jabłko").
  4. Używając instrukcji switch, wyświetl komentarz na temat tego owocu. Obsłuż co najmniej trzy różne owoce i dodaj blok default dla nieznanych owoców. Pamiętaj o break.

Pokaż przykładowe rozwiązanie
<?php
// 1. Pobranie aktualnej godziny
$godzina = (int)date("G"); // Rzutowanie na int dla pewności

echo "<h3>Powitanie zależne od pory dnia (jest godzina: $godzina):</h3>";
// 2. Instrukcja if...elseif...else dla pory dnia
if ($godzina >= 6 && $godzina <= 11) {
    echo "Dzień dobry!<br>";
} elseif ($godzina >= 12 && $godzina <= 17) {
    echo "Miłego popołudnia!<br>";
} elseif ($godzina >= 18 && $godzina <= 21) {
    echo "Dobry wieczór!<br>";
} else {
    echo "Dobrej nocy!<br>";
}

// 3. Ulubiony owoc
$ulubionyOwoc = "banan"; // Możesz zmienić na "jabłko", "truskawka" lub inny

echo "<h3>Komentarz o owocu ($ulubionyOwoc):</h3>";
// 4. Instrukcja switch dla owocu
switch (strtolower($ulubionyOwoc)) { // Konwersja na małe litery dla ułatwienia porównania
    case "jabłko":
        echo "Jabłka są zdrowe i chrupiące!<br>";
        break;
    case "banan":
        echo "Banany są świetnym źródłem potasu.<br>";
        break;
    case "truskawka":
        echo "Truskawki to smak lata!<br>";
        break;
    default:
        echo "Nie mam specjalnego komentarza na temat owocu: " . htmlspecialchars($ulubionyOwoc) . ".<br>";
}
?>
            

Zadanie do samodzielnego wykonania

Napisz skrypt, który symuluje prosty kalkulator ocen. Zadeklaruj zmienną $procentWyniku (0-100). Używając instrukcji if...elseif...else, przypisz do zmiennej $ocenaSlowna odpowiednią ocenę słowną (np. "Niedostateczny", "Dopuszczający", "Dostateczny", "Dobry", "Bardzo dobry", "Celujący") na podstawie progów procentowych, które sam ustalisz. Wyświetl procent wyniku i uzyskaną ocenę słowną. Spróbuj również zaimplementować to samo za pomocą alternatywnej składni instrukcji warunkowych (z dwukropkami).


FAQ - Instrukcje Warunkowe w PHP

Czy mogę zagnieżdżać instrukcje if wewnątrz innych instrukcji if?

Tak, można zagnieżdżać instrukcje if (oraz inne instrukcje warunkowe i pętle) wewnątrz siebie. Pozwala to na tworzenie bardziej złożonej logiki. Należy jednak dbać o czytelność kodu i unikać zbyt głębokiego zagnieżdżania, które może utrudnić zrozumienie programu.

Jaka jest różnica między elseif a else if?

Funkcjonalnie nie ma żadnej różnicy – oba zapisy działają identycznie. elseif jest po prostu alternatywnym zapisem dla else if (ze spacją). Większość programistów PHP preferuje zapis elseif jako jedno słowo kluczowe dla spójności.

Co się stanie, jeśli w instrukcji switch pominę blok default?

Blok default w instrukcji switch jest opcjonalny. Jeśli zostanie pominięty, a wartość wyrażenia w switch nie pasuje do żadnego z bloków case, to po prostu żaden kod wewnątrz switch nie zostanie wykonany, a program przejdzie do instrukcji po switch.

Czy mogę używać wyrażeń jako wartości w blokach case instrukcji switch?

Nie, wartości w blokach case muszą być stałymi literałami (np. liczby, ciągi znaków) lub stałymi zdefiniowanymi za pomocą const lub define(). Nie można tam używać zmiennych ani wyników funkcji bezpośrednio jako wartości case. Instrukcja switch porównuje wartość wyrażenia switch z tymi stałymi wartościami.

Kiedy lepiej użyć switch, a kiedy if...elseif...else?

switch jest zazwyczaj lepszym wyborem, gdy porównujesz jedną zmienną z wieloma konkretnymi, dyskretnymi wartościami. Kod jest wtedy często bardziej czytelny. if...elseif...else jest bardziej elastyczne i lepiej nadaje się do sprawdzania złożonych warunków, zakresów wartości, lub gdy warunki dotyczą różnych zmiennych.

Czy instrukcja switch w PHP używa ścisłego (===) czy luźnego (==) porównania?

Porównanie w instrukcji switch w PHP jest generalnie luźne (jak ==). Oznacza to, że PHP może dokonywać konwersji typów. Na przykład, switch ("0") { case 0: ... } dopasuje się. Jednak od PHP 8.0.0, zachowanie przy porównywaniu nie-numerycznych ciągów z liczbami stało się bardziej przewidywalne i bliższe ścisłemu porównaniu w niektórych przypadkach. Dla pewności najlepiej jest używać tego samego typu danych w wyrażeniu switch i w wartościach case.

Czy mogę użyć alternatywnej składni (z dwukropkami) dla instrukcji switch?

Tak, PHP oferuje również alternatywną składnię dla instrukcji switch, która wygląda następująco: switch (wyrazenie): case wartosc1: ... break; ... default: ... endswitch;. Jest ona analogiczna do alternatywnej składni dla if i może być użyteczna w szablonach HTML.