Instrukcje warunkowe if, elseif, switch i match oraz pętle for, while, do...while i foreach w PHP: kiedy sprawdzany jest warunek, ile obrotów wykona pętla, po co są break i continue oraz jak pętla generuje listę i tabelę HTML. Lekcja 12.3 kursu INF.03.
Instrukcja sterująca to konstrukcja języka, która decyduje, CZY i ILE RAZY wykona się fragment kodu: warunek wybiera jedną z dróg, pętla powtarza ten sam blok. Bez nich skrypt PHP idzie od góry do dołu i za każdym razem robi to samo. W części pisemnej wracają pytania z ramką kodu („ile iteracji zrealizuje przedstawiona pętla", „jaki ciąg liczb wypisze pętla", „jaką wartość przyjmie zmienna po zakończeniu pętli", „która pętla wykona się co najmniej raz", „do czego służy break"). W zadaniu praktycznym pętla while przechodzi po wierszach zapytania i generuje z nich <li> albo <tr>, a if sprawdza, czy formularz został już wysłany.
Warunek: if, else, elseif
if (JEŻELI) to instrukcja wykonująca blok w nawiasach klamrowych tylko wtedy, gdy warunek w nawiasach okrągłych jest prawdziwy. else (W PRZECIWNYM RAZIE) dokłada drugą drogę, na którą skrypt wchodzi przy warunku niespełnionym, a elseif (A JEŻELI) wstawia między nie kolejne pytanie. Warunki elseif sprawdzane są po kolei, od góry: pierwszy prawdziwy wygrywa, reszta zostaje pominięta.
<?php
$kwota = 250;
if ($kwota >= 500) {
$rabat = 10;
} elseif ($kwota >= 200) {
$rabat = 5;
} else {
$rabat = 0;
}
echo "Rabat: $rabat procent";
Wynik: Rabat: 5 procent. Kwota 250 nie przeszła pierwszego warunku, przeszła drugi, więc else nic już nie robi. Zapis else if z odstępem znaczy to samo co elseif, poza składnią alternatywną z dwukropkiem, gdzie działa wyłącznie elseif.
Warunek złożony łączy kilka porównań operatorami logicznymi: && (I) wymaga obu części, || (LUB) wystarczy jedna, ! (NIE) odwraca wynik. Operator && łączy mocniej niż ||, więc grupy trzeba zamykać w nawiasach.
<?php
$ulica = "Bratkowa";
$numer = 12;
if (($ulica == "Bratkowa" || $ulica == "Nasturcjowa") && $numer % 2 == 0) {
echo "Adres pasuje";
}
Wynik: Adres pasuje. Bez nawiasu wokół dwóch nazw ulic warunek sprawdzałby co innego: pierwszą ulicę samodzielnie albo drugą z parzystym numerem.
Skrótem dla najprostszego wyboru jest operator trójargumentowy: warunek, znak zapytania, wartość dla prawdy, dwukropek, wartość dla fałszu.
<?php
$kwota = 250;
$rabat = $kwota >= 200 ? 5 : 0;
echo $rabat;
Wynik: 5.
Pułapka: = przypisuje wartość, == porównuje wartości, a === porównuje wartość i typ. Warunek if ($a = 5) jest zawsze prawdziwy, bo najpierw przypisuje 5, a potem oddaje tę piątkę jako wynik.
switch, case i match
switch (PRZEŁĄCZ) to instrukcja wyboru, która porównuje JEDNĄ wartość z listą przypadków case (PRZYPADEK) i wykonuje kod od pierwszego pasującego. Zastępuje długi łańcuch elseif o wciąż tej samej zmiennej. break kończy całą instrukcję, a default (DOMYŚLNY) łapie to, co nie pasowało do żadnego przypadku.
<?php
$dzien = 3;
switch ($dzien) {
case 1:
echo "Poniedziałek";
break;
case 6:
case 7:
echo "Weekend";
break;
default:
echo "Dzień roboczy";
}
Wynik: Dzień roboczy. Dwa przypadki jeden pod drugim bez break to zabieg celowy: 6 i 7 prowadzą do tego samego kodu. Zapomniany break w środku bloku daje przelot, czyli wykonanie także kolejnych przypadków, bez sprawdzania ich wartości.
<?php
$ocena = 5;
switch ($ocena) {
case 5:
echo "bardzo dobry ";
case 4:
echo "dobry ";
default:
echo "koniec";
}
Wynik: bardzo dobry dobry koniec, choć ocena była tylko jedna. Obowiązkowa jest sama konstrukcja switch z wyrażeniem w nawiasie: ani default, ani break po każdym przypadku, ani dwa przypadki nie są wymagane.
match z PHP 8 robi to samo krócej: porównuje operatorem ===, więc wartość i typ muszą się zgadzać, nie potrzebuje break, zwraca wartość zamiast wypisywać, a gdy nic nie pasuje i nie ma default, zgłasza błąd.
<?php
$dzien = 7;
$nazwa = match ($dzien) {
6, 7 => "weekend",
default => "dzień roboczy",
};
echo $nazwa;
Wynik: weekend.
Pętle: for, while i do...while
Pętla to instrukcja powtarzająca ten sam blok kodu, dopóki jej warunek jest prawdziwy. Jedno wykonanie bloku to obrót, inaczej iteracja, i to jego liczby dotyczy większość pytań.
for (DLA) trzyma w nawiasie trzy części rozdzielone średnikami: początkową wartość licznika, warunek trwania pętli i krok wykonywany po każdym obrocie. Nadaje się tam, gdzie liczba powtórzeń jest znana z góry.
<?php
for ($i = 5; $i <= 20; $i += 5) {
echo $i . " ";
}
Obrót
$i na wejściu
Warunek $i <= 20
Co wypisze
$i po kroku
5
25
fałsz
nic, koniec pętli
25
Wynik: 5 10 15 20, czyli cztery obroty. Gdyby warunek brzmiał $i < 20, obrotów byłoby trzy, bo dwudziestka już by nie weszła.
while (DOPÓKI) sprawdza warunek PRZED każdym obrotem, więc gdy jest on fałszywy od początku, blok nie wykona się ani razu. Pasuje tam, gdzie nie wiadomo z góry, ile będzie powtórzeń: tak właśnie przechodzi się po wierszach zapytania do bazy.
do...while (WYKONUJ DOPÓKI) sprawdza warunek na KOŃCU obrotu, więc blok wykonuje się co najmniej raz, nawet przy warunku fałszywym. Po zamykającym nawiasie stoi średnik.
<?php
$i = 1;
do {
echo $i;
$i++;
} while ($i > 5);
Wynik: 1, jeden obrót mimo fałszywego warunku.
Biegiem pętli sterują dwa słowa. break przerywa całą pętlę i przenosi wykonanie za jej klamrę, a continue (KONTYNUUJ) przerywa tylko bieżący obrót i przechodzi do następnego. W pętli zagnieżdżonej break wychodzi z jednej pętli, a break 2 z dwóch naraz.
Pętla nieskończona to taka, której warunek nigdy nie staje się fałszywy: while (true) albo while ($i < 10) z zapomnianym zwiększaniem $i. Wychodzi się z niej przez break, inaczej skrypt wisi do limitu czasu z php.ini.
Pętla
Kiedy sprawdza warunek
Minimum wykonań
Do czego
for
przed obrotem
0
znana z góry liczba powtórzeń, licznik
while
przed obrotem
0
powtarzanie do skutku, wiersze zapytania
do...while
po obrocie
1
gdy blok ma wykonać się choć raz
foreach
przed obrotem
0
wszystkie elementy tablicy
foreach i pętle w kodzie HTML
foreach (DLA KAŻDEGO) to pętla przechodząca po wszystkich elementach tablicy, bez licznika i bez sprawdzania jej długości. Ma dwie postacie: $tablica as $wartosc daje same wartości, a $tablica as $klucz => $wartosc daje przy okazji indeks, pod którym wartość leży. Same tablice opisuje lekcja o tablicach w PHP. <?php
$produkty = ["Klawiatura", "Mysz", "Monitor 24"];
echo "<ol>";
foreach ($produkty as $nazwa) {
echo "<li>" . $nazwa . "</li>";
}
echo "</ol>";
Skrypt wypisuje nie listę, tylko jej kod, który przeglądarka rysuje jako listę numerowaną od 1 do 3:
<ol><li>Klawiatura</li><li>Mysz</li><li>Monitor 24</li></ol>
Postać z kluczem przydaje się przy cenniku: foreach ($ceny as $nazwa => $cena) daje w kolejnych obrotach parę nazwa i cena, gotową do wypisania w jednym wierszu.
Wiersze tabeli generuje while, bo liczba wierszy zwróconych przez zapytanie nie jest znana z góry. Funkcja mysqli_fetch_array oddaje kolejny wiersz wyniku, a gdy wierszy zabraknie, zwraca fałsz i pętla się kończy. Połączenie z bazą opisuje lekcja PHP i baza danych. <?php
$wynik = mysqli_query($polaczenie, "SELECT nazwa, cena FROM produkt");
echo "<table>";
while ($wiersz = mysqli_fetch_array($wynik)) {
echo "<tr><td>" . $wiersz['nazwa'] . "</td><td>" . $wiersz['cena'] . "</td></tr>";
}
echo "</table>";
Wynik: jeden <tr> na każdy produkt z tabeli produkt.
Gdy w pętli jest więcej HTML niż PHP, wygodniejsza bywa składnia alternatywna: klamrę otwierającą zastępuje dwukropek, a zamykającą słowo endforeach, endwhile, endfor albo endif. Znaczniki zostają wtedy zwykłym HTML zamiast napisów sklejanych w echo.
<ul>
<?php foreach ($produkty as $nazwa): ?>
<li><?php echo $nazwa; ?></li>
<?php endforeach; ?>
</ul>
Wynik jest taki sam jak przy pętli z echo: <li> z nazwami produktów w środku <ul>.
Trzy klocki: sekwencja, wybór, iteracja
Programowanie strukturalne to sposób pisania programów, w którym cały kod składa się z trzech konstrukcji: sekwencji (instrukcje wykonywane jedna po drugiej), wyboru (if, switch) i iteracji (pętle). Każdy blok ma jedno wejście i jedno wyjście, a skoków w dowolne miejsce kodu nie ma. Stąd wcięcia: wcięty wiersz należy do klamry stojącej wyżej.
Zapisanie algorytmu w PHP to złożenie jego kroków z tych trzech klocków. Suma liczb z tablicy to iteracja plus sekwencja dodawania, a średnia to jedno dzielenie po wyjściu z pętli.
<?php
$oceny = [5, 3, 4, 6, 2];
$suma = 0;
foreach ($oceny as $ocena) {
$suma += $ocena;
}
$srednia = $suma / count($oceny);
echo "Suma: $suma, średnia: $srednia";
Wynik: Suma: 20, średnia: 4.
Szukanie największego elementu dokłada do pętli wybór: do zmiennej pomocniczej wpisuje się PIERWSZY element tablicy, a potem każdy kolejny porównuje się z nią i podmienia, gdy jest większy. Start od zera zamiast od pierwszego elementu psuje ten algorytm dla tablicy z samymi liczbami ujemnymi. Zliczanie liczb parzystych to licznik rosnący tylko wtedy, gdy reszta z dzielenia przez 2 wynosi zero, czyli gdy $liczba % 2 == 0. Silnia mnoży w pętli kolejne liczby przez wynik z poprzedniego obrotu.
<?php
$n = 5;
$silnia = 1;
for ($i = 2; $i <= $n; $i++) {
$silnia *= $i;
}
echo $silnia;
Wynik: 120.
Rachunek iteracji krok po kroku
Pytanie o liczbę obrotów rozwiązuje się zawsze tak samo: wypisz licznik na wejściu, sprawdź warunek, dopisz krok i powtórz do pierwszego fałszu. Ten sam rachunek pokaże w przeglądarce interpreter PHP: każdy obrót pętli jest w nim osobnym krokiem z wartością licznika. <?php
for ($i = 0; $i < 10; $i += 2) {
echo $i . " ";
}
Licznik przyjmuje kolejno 0, 2, 4, 6, 8, a przy 10 warunek $i < 10 jest już fałszywy, więc obrotów jest pięć, a wynik to 0 2 4 6 8. Ten sam kod z warunkiem $i <= 10 daje sześć obrotów i dopisuje na końcu 10.
<?php
$x = 1;
while ($x < 100) {
$x *= 2;
}
echo $x;
Wartości $x to 1, 2, 4, 8, 16, 32, 64 i 128. Ostatni obrót zaczyna się przy 64 i kończy podwojeniem do 128, a warunek 128 < 100 jest już fałszywy: wynik to 128 po siedmiu obrotach. Pętla do...while z warunkiem fałszywym od początku, jak $i > 5 przy $i równym 1, wykona się dokładnie raz.
<?php
$suma = 0;
for ($i = 1; $i <= 10; $i++) {
if ($suma > 10) {
break;
}
$suma += $i;
}
echo $suma;
Suma rośnie 1, 3, 6, 10, 15. Na szóstym obrocie warunek $suma > 10 jest prawdziwy, break wychodzi z pętli przed dodaniem szóstki i wynikiem jest 15. Z continue pętla doszłaby do dziesiątego obrotu, nic już nie dodając, więc wynik byłby ten sam.
Na egzaminie
Pytania pisemne o instrukcje sterujące mają kilka stałych kształtów. Ramka z pętlą i pytanie o liczbę iteracji albo o wypisany ciąg liczb: policz wartości licznika, pamiętając, że warunek ze znakiem < daje o jeden obrót mniej niż ten sam warunek ze znakiem <=. Ramka z pętlą i pytanie o wartość zmiennej po jej zakończeniu: prześledź obroty do pierwszego fałszywego warunku. Pętla wykonująca się co najmniej raz to do...while, pętla po wszystkich elementach tablicy z automatycznym indeksowaniem to foreach, a instrukcja przeznaczona do wykonania określonej liczby iteracji to for, nie switch ani if. Pytanie o instrukcję równoważną podanemu switch: to łańcuch if i elseif porównujących tę samą zmienną z kolejnymi wartościami, z else w miejscu default.
Kilka odpowiedzi myli się regularnie. break przerywa całą pętlę, a continue tylko bieżący obrót, więc po continue pętla kręci się dalej. W instrukcji switch obowiązkowa jest sama konstrukcja z wyrażeniem w nawiasie, a nie default ani break. Warunek na przedział od 2 do 6 wymaga &&, bo wersja z || jest prawdziwa dla dowolnej liczby, a liczbę parzystą wybiera reszta z dzielenia przez 2 równa zeru, nie iloraz.
W zadaniu praktycznym polecenie brzmi zwykle: „lista numerowana wypełniana przez skrypt" albo „dane wyświetlone w tabeli". Pierwsze to <ol> wypisane raz, a w środku <li> generowane w pętli while po kolejnych wierszach zapytania. Drugie to <table> z <tr> w tej samej pętli. Instrukcja if sprawdza tam, czy połączenie z bazą się udało i czy formularz został już wysłany. Formularz i odbiór jego danych opisują lekcje o formularzach HTML i obsłudze GET i POST. Ściąga
if (warunek) { }
wykonaj blok, gdy warunek jest prawdziwy
elseif (warunek) { }
kolejne pytanie, sprawdzane po nieudanym poprzednim
else { }
droga na wypadek, gdy żaden warunek nie był prawdziwy
$a = $x > 0 ? 1 : 0;
operator trójargumentowy, skrót zapisu if i else
switch ($x) { case 1: ... }
wybór jednego przypadku z listy, po nim break
default:
przypadek dla wartości spoza listy, nieobowiązkowy
match ($x) { 1 => "a" }
wybór z PHP 8, porównuje === i zwraca wartość
for ($i = 0; $i < 10; $i++)
10 obrotów, licznik od 0 do 9
while ($i < 10)
warunek przed obrotem, może nie wykonać się ani razu
do { } while ($i < 10);
warunek po obrocie, wykona się co najmniej raz
foreach ($tab as $wartosc)
po wszystkich elementach tablicy, bez licznika
foreach ($tab as $klucz => $wartosc)
to samo, z indeksem elementu
break;
wyjście z całej pętli albo z instrukcji switch
continue;
pominięcie reszty obrotu, przejście do następnego
endforeach;
zamknięcie pętli w składni alternatywnej z dwukropkiem
Pobierz ściągę PDF