PHP gestisce molto lavoro ripetitivo sul lato server. Una singola richiesta potrebbe dover scansionare una cartella piena di immagini, interrogare un database finché uno stato non cambia, o continuare a chiedere un input all'utente finché non soddisfa le tue regole. Fare una cosa del genere copiando e incollando lo stesso blocco di codice sarebbe fragile e quasi impossibile da mantenere. I cicli esistono proprio per risolvere questo problema. Racchiudono la logica in un blocco riutilizzabile, riducono gli errori e mantengono l'applicazione compatta.

La maggior parte degli sviluppatori PHP ricorre istintivamente a un ciclo for quando sa quante iterazioni sono necessarie, o a un ciclo while quando il conteggio dipende da una condizione dinamica. Esiste però una terza opzione, che si comporta in modo sufficientemente diverso da poter rendere il codice significativamente più chiaro se scelta nel momento giusto. Il ciclo do-while esegue prima il codice all'interno del suo blocco, poi controlla se deve essere eseguito di nuovo.

Cosa rende diverso il ciclo do-while

In un ciclo while standard, PHP valuta la condizione prima ancora di entrare nel blocco. Se la condizione è falsa fin dall'inizio, il blocco viene saltato interamente. Un ciclo do-while inverte questo ordine. Esegue il codice una volta, arriva alla fine e solo allora controlla la condizione per decidere se ricominciare il ciclo.

La sintassi è la seguente:

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

Nota il punto e virgola dopo la clausola while. Quel punto e virgola è obbligatorio, e dimenticarlo causerà un errore di sintassi. Il blocco tra do e while viene eseguito sempre almeno una volta, anche se la condizione è falsa fin dall'inizio. Questo comportamento post-test non è solo una particolarità; è la ragione stessa per cui il ciclo esiste.

Quando ricorrere al do-while

Ci sono tre scenari comuni in cui questa struttura eccelle: visualizzare un menu, validare un input e riprovare un'operazione che potrebbe fallire. In ogni caso, la logica richiede che l'azione avvenga prima di poter decidere se continuare.

Visualizzare un menu

Immagina uno strumento da riga di comando o un pannello di amministrazione testuale. Devi stampare un elenco di opzioni, attendere che l'utente ne scelga una e poi decidere se mostrare nuovamente il menu. Non puoi controllare se l'utente ha scelto di uscire finché il menu non è già apparso sullo schermo.

$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);

Un normale ciclo while potrebbe tecnicamente gestire la cosa, ma ti costringerebbe a ripetere l'output del menu una volta prima dell'inizio del ciclo, o a inizializzare $choice con un valore fittizio solo per soddisfare la condizione iniziale. Ciò disperde la logica correlata in due punti diversi. La versione do-while mantiene la visualizzazione, la lettura e il controllo all'interno di un unico blocco ordinato.

Validare l'input

La validazione dell'input segue spesso lo stesso schema. Vuoi sollecitare l'utente, ispezionare ciò che ti ha fornito e ripetere se non rispetta le tue regole. Poiché il prompt deve avvenire prima dell'ispezione, un ciclo do-while si adatta naturalmente.

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

Con un ciclo while standard, dovresti inizializzare $username con una stringa vuota e duplicare la riga del prompt sopra il ciclo, in modo che la condizione abbia qualcosa da valutare. Questa ripetizione invita ai bug. Se in seguito cambi il messaggio del prompt, potresti ricordarti di modificarlo all'interno del ciclo ma dimenticare la copia sovrastante. La struttura do-while elimina questo rischio garantendo che il prompt venga eseguito all'interno del blocco prima che venga testata qualsiasi condizione.

Riprovare un'operazione fallita

Le richieste di rete, i blocchi dei file e le scritture nel database a volte falliscono al primo tentativo ma hanno successo poco dopo. Di solito si vuole provare almeno una volta, per poi continuare a provare solo finché l'errore persiste e si ha ancora pazienza.

$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
}

Il dettaglio cruciale qui è che la richiesta viene inviata prima che PHP si chieda: "Ha funzionato?". Un ciclo while dovrebbe eseguire una richiesta fittizia o impostare un falso flag di successo prima di entrare nel ciclo, il che oscurerebbe ciò che sta accadendo realmente. La versione do-while rende la sequenza onesta: prova, ispeziona e decidi.

Confronto tra do-while e while

La differenza tra questi due cicli è una questione di tempistica. Considera una variabile che inizia in uno stato che fallirebbe qualsiasi test:

$x = 10;

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

Con lo stesso valore iniziale, un ciclo do-while si comporta così:

$x = 10;

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

Quella singola esecuzione garantita è il fattore decisivo. Se la tua logica richiede zero o più iterazioni, while è lo strumento più sicuro. Se la tua logica richiede una o più iterazioni, do-while è solitamente lo strumento più pulito.

Errori comuni e buone pratiche

Poiché il ciclo do-while garantisce almeno un'esecuzione, può anche causare un loop infinito se non si presta attenzione. Se le variabili controllate nella condizione non cambiano mai all'interno del blocco, PHP continuerà a girare all'infinito o fino al raggiungimento del tempo massimo di esecuzione.

Un altro errore comune è l'omissione del punto e virgola finale. Il seguente esempio fallirà:

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

Dovresti anche evitare di ricorrere al do-while per abitudine quando un altro ciclo è più espressivo. Se stai iterando su un array, il foreach è quasi sempre superiore. Se stai gestendo un semplice contatore numerico, un ciclo for mantiene l'inizializzazione, la condizione e l'incremento in un'unica riga, rendendolo più facile da leggere.

In termini di prestazioni, il do-while non comporta alcun overhead significativo rispetto al while in PHP. Il vantaggio è interamente strutturale. Quando un altro sviluppatore vede un ciclo do-while, capisce immediatamente che il blocco deve essere eseguito prima che venga valutata qualsiasi condizione. Questa singola informazione evita di dover tracciare variabili dummy o codice di configurazione duplicato sopra un normale ciclo while.

Casi limite e pattern alternativi

A volte un ciclo do-while è utile anche quando non è coinvolta alcuna interazione dell'utente. Ad esempio, quando si consuma un generatore o un cursore che restituisce almeno un elemento, è possibile elaborare il primo elemento e poi verificare se il cursore è avanzato a una posizione successiva valida. Nei codebase legacy che utilizzano risorse database grezze invece di moderni set di risultati, potresti trovare un pattern come questo:

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

Sebbene il PHP moderno prediliga il foreach con PDO, questo pattern illustra come il do-while gestisca la prima iterazione come un caso speciale senza ramificazioni extra.

Conclusione

Il ciclo do-while è uno strumento specifico, ma nel posto giusto è l'unico che ha senso usare. Mantiene la logica di configurazione e di validazione in un unico punto, garantisce che un'azione venga tentata prima di essere giudicata e comunica chiaramente l'intento alla persona che leggerà il codice successivamente. Quando la condizione deve verificarsi dopo il lavoro, usa il do-while. In tutti gli altri casi, lascia che il più semplice while, for o foreach faccia il lavoro.