PHP obsługuje wiele powtarzalnych zadań po stronie serwera. Pojedyncze żądanie może wymagać przeskanowania folderu pełnego obrazów, odpytywania bazy danych, aż do zmiany statusu, lub ciągłego proszenia użytkownika o dane wejściowe, dopóki nie spełnią one Twoich reguł. Kopiowanie i wklejanie tego samego bloku kodu byłoby rozwiązaniem podatnym na błędy i niemal niemożliwym do utrzymania. Pętle istnieją właśnie po to, aby rozwiązać ten problem. Zamykają one logikę w wielokrotnego użytku bloku, ograniczają liczbę błędów i sprawiają, że aplikacja pozostaje kompaktowa.

Większość programistów PHP instynktownie sięga po pętlę for, gdy wiedzą, ile iteracji jest potrzebnych, lub po pętlę while, gdy liczba zależy od dynamicznego warunku. Istnieje jednak trzecia opcja, która zachowuje się na tyle inaczej, że jej właściwy wybór może znacząco poprawić czytelność kodu. Pętla do-while najpierw wykonuje kod wewnątrz swojego bloku, a dopiero potem sprawdza, czy powinna uruchomić go ponownie.

Co wyróżnia pętlę do-while

W standardowej pętli while PHP sprawdza warunek, zanim jeszcze wejdzie do bloku kodu. Jeśli warunek na początku jest fałszywy, blok jest całkowicie pomijany. Pętla do-while odwraca tę kolejność. Uruchamia kod raz, dociera do końca, a dopiero potem sprawdza warunek, aby zdecydować, czy wrócić do początku pętli.

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

do {
    // statements
} while ($condition);

Zauważ średnik po klauzuli while. Ten średnik jest wymagany, a jego brak spowoduje błąd składni. Blok między do a while zawsze wykonuje się co najmniej raz, nawet jeśli warunek jest fałszywy od samego początku. To zachowanie typu post-test nie jest tylko ciekawostką; to właśnie główny powód istnienia tej pętli.

Kiedy sięgać po do-while

Istnieją trzy powszechne scenariusze, w których ta struktura sprawdza się najlepiej: wyświetlanie menu, walidacja danych wejściowych oraz ponawianie zadania, które mogło zakończyć się niepowodzeniem. W każdym z tych przypadków logika wymaga, aby akcja została wykonana, zanim będzie można ocenić, czy należy kontynuować.

Wyświetlanie menu

Wyobraź sobie narzędzie wiersza poleceń lub tekstowy panel administracyjny. Musisz wyświetlić listę opcji, poczekać, aż użytkownik wybierze jedną, a następnie zdecydować, czy ponownie pokazać menu. Nie możesz sprawdzić, czy użytkownik wybrał wyjście, dopóki menu nie pojawi się na ekranie.

$choice = 0;

do {
    echo "1. View Reports\n";
    echo "2. Export Data\n";
    echo "3. Exit\n";
    
    $choice = (int) readline("Select an option: ");
    
    if ($choice === 1) {
        // fetch and display reports
    } elseif ($choice === 2) {
        // run export logic
    }
} while ($choice !== 3);

Zwykła pętla while technicznie mogłaby sobie z tym poradzić, ale wymusiłaby powtórzenie wyświetlania menu raz przed rozpoczęciem pętli lub zainicjowanie zmiennej $choice jakąś sztuczną wartością tylko po to, aby spełnić początkowy warunek. Powoduje to rozproszenie powiązanej logiki w dwóch miejscach. Wersja do-while utrzymuje wyświetlanie, odczyt i sprawdzenie wewnątrz jednego, uporządkowanego bloku.

Walidacja danych wejściowych

Walidacja danych wejściowych często podąża za tym samym wzorcem. Chcesz poprosić użytkownika o dane, sprawdzić to, co podał, i powtórzyć proces, jeśli nie spełni on Twoich reguł. Ponieważ prośba musi nastąpić przed sprawdzeniem, pętla do-while pasuje tutaj naturalnie.

do {
    $username = readline("Choose a username (min 3 chars): ");
    $isValid = strlen($username) >= 3;
    
    if (!$isValid) {
        echo "That username is too short.\n";
    }
} while (!$isValid);

Przy standardowej pętli while musiałbyś zainicjować $username pustym ciągiem znaków i powielić linię z prośbą o dane nad pętlą, aby warunek miał coś do sprawdzenia. Takie powtórzenie sprzyja błędom. Jeśli później zmienisz treść komunikatu, możesz pamiętać o edycji wewnątrz pętli, ale zapomnieć o kopii znajdującej się powyżej. Struktura do-while eliminuje to ryzyko, gwarantując, że komunikat zostanie wyświetlony wewnątrz bloku przed sprawdzeniem jakiegokolwiek warunku.

Ponawianie nieudanego zadania

Żądania sieciowe, blokady plików i zapisy do bazy danych czasami zawodzą przy pierwszej próbie, ale po chwili kończą się sukcesem. Zazwyczaj chcesz spróbować przynajmniej raz, a następnie kontynuować próby tylko tak długo, jak błąd występuje i dopóki masz jeszcze cierpliwość.

$attempts = 0;
$maxRetries = 3;
$success = false;

do {
    $attempts++;
    $response = @file_get_contents('https://api.example.com/status');
    
    if ($response !== false) {
        $success = true;
    } elseif ($attempts < $maxRetries) {
        sleep(1);
    }
} while (!$success && $attempts < $maxRetries);

if (!$success) {
    // log the permanent failure
}

Kluczowym szczegółem jest tutaj to, że żądanie jest wysyłane, zanim PHP w ogóle zapyta: „Czy to zadziałało?”. Pętla while musiałaby wykonać pozorne żądanie lub ustawić fałszywą flagę sukcesu przed wejściem do pętli, co zaciemniłoby to, co faktycznie się dzieje. Wersja do-while sprawia, że sekwencja jest uczciwa: próba, sprawdzenie i decyzja.

Porównanie do-while i while

Różnica między tymi dwiema pętlami polega na czasie wykonania. Rozważmy zmienną, która znajduje się w stanie, który spowodowałby niepowodzenie każdego testu:

$x = 10;

while ($x < 5) {
    echo $x;        // Never runs
}

Przy tej samej wartości początkowej pętla do-while zachowuje się w następujący sposób:

$x = 10;

do {
    echo $x;        // Runs once, outputs 10
} while ($x < 5);

To pojedyncze, gwarantowane wykonanie jest decydującym czynnikiem. Jeśli Twoja logika wymaga zero lub więcej iteracji, while jest bezpieczniejszym narzędziem. Jeśli Twoja logika wymaga jednej lub więcej iteracji, do-while jest zazwyczaj czystszym rozwiązaniem.

Pułapki i dobre praktyki

Ponieważ pętla do-while gwarantuje co najmniej jedno wykonanie, może również doprowadzić do nieskończonej pętli, jeśli nie będziesz ostrożny. Jeśli zmienne sprawdzane w warunku nigdy nie zmienią się wewnątrz bloku, PHP będzie działać w nieskończoność lub do momentu przekroczenia maksymalnego czasu wykonywania.

Innym częstym błędem jest pominięcie średnika na końcu. Poniższy przykład zakończy się błędem:

do {
    // code
} while ($x < 5)    // syntax error

Powinieneś również unikać sięgania po do-while z przyzwyczajenia, gdy inna pętla jest bardziej czytelna. Jeśli iterujesz po tablicy, foreach jest prawie zawsze lepszym rozwiązaniem. Jeśli zarządzasz prostym licznikiem numerycznym, pętla for utrzymuje inicjalizację, warunek i inkrementację w jednej linii, co ułatwia szybki przegląd kodu.

Pod względem wydajności do-while nie generuje znaczącego narzutu w porównaniu do while w PHP. Korzyść ma charakter wyłącznie strukturalny. Gdy inny programista widzi pętlę do-while, natychmiast rozumie, że blok musi zostać wykonany, zanim jakikolwiek warunek zostanie oceniony. Ta pojedyncza informacja oszczędza mu śledzenia zmiennych pomocniczych lub powielonego kodu konfiguracyjnego nad standardową pętlą while.

Przypadki brzegowe i alternatywne wzorce

Czasami pętla do-while jest przydatna nawet wtedy, gdy nie ma interakcji z użytkownikiem. Na przykład podczas korzystania z generatora lub kursora, który zwraca co najmniej jeden element, możesz przetworzyć pierwszy element, a następnie sprawdzić, czy kursor przesunął się na kolejną poprawną pozycję. W starszych bazach kodu (legacy), które używają surowych zasobów bazy danych zamiast nowoczesnych zestawów wyników, możesz spotkać wzorzec taki jak ten:

$row = $result->fetch();
do {
    // process $row
} while ($row = $result->fetch());

Choć nowoczesne PHP faworyzuje foreach z PDO, wzorzec ten ilustruje, jak do-while obsługuje pierwszą iterację jako przypadek specjalny bez dodatkowych rozgałęzień.

Najważniejszy wniosek

Pętla do-while to wyspecjalizowane narzędzie, ale w odpowiednim miejscu jest to jedyne narzędzie, które ma sens. Pozwala ona utrzymać logikę konfiguracji i walidacji w jednym miejscu, gwarantuje, że próba wykonania akcji nastąpi przed jej oceną i bezpośrednio komunikuje Twoje zamiary osobie czytającej kod. Gdy warunek musi wystąpić po wykonaniu pracy, użyj do-while. W każdym innym przypadku pozwól prostszym pętlom while, for lub foreach wykonać zadanie.