Aggiornare la versione di PHP in un’applicazione esistente non significa soltanto cambiare l’immagine del container o la configurazione del server. Il runtime interagisce con il codice, le estensioni, le librerie Composer e i processi che eseguono attività pianificate o job in background. Un cambiamento può influire su ciascuno di questi elementi, anche se l’applicazione sembra funzionare normalmente durante un test manuale.
Per ridurre l’incertezza, occorre trattare l’aggiornamento come un cambiamento di compatibilità: censire ciò che viene eseguito, cercare le incompatibilità, validare percorsi rappresentativi e definire in anticipo come decidere se la distribuzione prosegue o viene ripristinata. L’obiettivo è isolare il lavoro necessario per il nuovo runtime, non trasformare l’aggiornamento in una riscrittura del prodotto.
Il runtime fa parte della compatibilità dell’applicazione

Una versione di PHP determina la sintassi supportata dall’interprete e il comportamento di determinate funzioni e tipi. Stabilisce inoltre quali versioni di estensioni e dipendenze possono essere installate. Perciò, il fatto che il codice abbia funzionato nell’ambiente attuale non dimostra che funzionerà anche nel nuovo: potrebbero cambiare una funzione, un’interfaccia, il comportamento dei tipi o la disponibilità di un’estensione.
È utile distinguere tre ambiti: il codice dell’applicazione, le dipendenze di terze parti e la configurazione dell’ambiente. Se vengono modificati tutti e tre contemporaneamente, è più difficile attribuire la causa di un problema. Quando possibile, un aggiornamento pianificato separa queste modifiche e mantiene esplicito quale componente ha introdotto ciascun adeguamento.
Fai l’inventario del runtime, delle dipendenze e dei processi
Prima di modificare qualsiasi cosa, registra l’ambiente di esecuzione effettivo, non solo quello descritto dal file di configurazione del progetto. Controlla la versione di PHP nei container o nei server che gestiscono le richieste e in quelli che eseguono attività pianificate, consumer di code e comandi di manutenzione. Questi processi potrebbero usare immagini, variabili o estensioni diverse.
- Runtime ed estensioni: identifica le estensioni abilitate, le relative versioni quando pertinente e le librerie di sistema da cui dipendono. Confronta i requisiti di produzione, CI e sviluppo.
- Dipendenze Composer: esamina
composer.json, il file di lock e i vincoli PHP dichiarati dai pacchetti. Controlla anche gli strumenti di sviluppo, come gli analizzatori e i test runner. - Configurazione: fai l’inventario dei valori di
php.ini, dei limiti di memoria e di tempo, della configurazione degli errori e delle impostazioni specifiche del server. Un nuovo runtime non garantisce che i parametri rilevanti siano stati mantenuti. - Attività esterne alle richieste web: includi cron, code, comandi da console, importazioni, esportazioni e attività di lunga durata. Il corretto funzionamento di un percorso web non convalida automaticamente questi flussi.
- Integrazioni e dati: annota i servizi esterni, i formati scambiati e le operazioni di scrittura su database o storage. Questo aiuta a individuare le operazioni che richiedono particolare attenzione in caso di rollback.
L’inventario può essere una lista mantenuta nel repository o nella documentazione operativa, purché consenta di confrontare gli ambienti e rilevare le discrepanze. Un sintomo frequente di un inventario incompleto è che CI passa, ma un worker o un’attività pianificata fallisce dopo la distribuzione.
Cerca le incompatibilità con più segnali
Inizia dagli strumenti automatizzati: controlla i vincoli di piattaforma di Composer ed esegui una verifica delle dipendenze con la versione di PHP di destinazione. Un conflitto nella risoluzione indica che un pacchetto, compresi gli strumenti di sviluppo, non dichiara la compatibilità con quella piattaforma. Non conviene forzare l’installazione per nascondere il conflitto senza capire quale requisito si sta aggirando.
Integra questa analisi con gli strumenti di analisi statica e con i test di stile o di compatibilità disponibili nel progetto. Possono segnalare utilizzi sospetti, API obsolete o pattern che meritano una verifica, ma da soli non dimostrano che l’intera applicazione funzioni. Allo stesso modo, un’analisi senza problemi non sostituisce l’esecuzione effettiva: alcuni errori emergono solo seguendo un ramo poco frequente o caricando un’estensione.
Esegui i test con il runtime di destinazione e le estensioni previste in produzione. Se la suite è limitata, aggiungi verifiche manuali o automatizzate dei flussi più critici: autenticazione, operazioni di scrittura, pagamenti, se presenti, generazione di documenti e integrazioni essenziali. Raccogli anche errori e avvisi: una modifica che trasforma un avviso in un’eccezione può interrompere un percorso prima che la suite riesca a rilevarlo.
Organizza il lavoro per isolare il rischio
Una sequenza pratica consiste nel verificare prima l’immagine o la configurazione candidata e le sue estensioni, poi risolvere i vincoli delle dipendenze e, infine, correggere il codice e le impostazioni che impediscono l’esecuzione dei test. Mantieni ogni gruppo di modifiche facile da esaminare. Se una libreria deve essere aggiornata, documenta quale requisito rende necessaria la modifica e verifica nell’applicazione le aree in cui viene utilizzata.
Evita di aggiornare indiscriminatamente tutte le dipendenze nello stesso passaggio. Un aggiornamento esteso può essere necessario, ma aumenta il numero delle possibili cause in caso di regressione. Se non è possibile separarlo, registra i pacchetti modificati e aggiungi test mirati alle funzionalità che ne dipendono. Assicurati inoltre che il file di lock venga generato e installato in modo coerente tra CI e produzione.
La configurazione deve rispecchiare la destinazione effettiva. Validare con un’estensione installata solo in CI produce un’indicazione fuorviante; lo stesso vale se le attività in background continuano a essere eseguite con il runtime precedente. Prima di attribuire un risultato al codice, confronta immagini, comandi di avvio, variabili e configurazione tra l’ambiente di test e quello di produzione.
Valida in un ambiente rappresentativo e definisci i criteri di uscita
CI deve eseguire installazione, analisi e test con il runtime di destinazione, non soltanto con quello attuale. Aggiungi job separati per altri runtime solo se l’applicazione deve mantenere una finestra di compatibilità: in tal caso, ogni combinazione supportata richiede una verifica esplicita. Una matrice CI può mostrare quali combinazioni vengono testate, ma non copre automaticamente le particolarità della produzione.
Usa un ambiente di preproduzione sufficientemente simile a quello reale per verificare l’avvio, i percorsi critici, le integrazioni, le code e le attività pianificate. Controlla log, errori, tempi di risposta e consumo delle risorse prima e dopo. Definisci in anticipo quale comportamento interromperebbe la distribuzione, chi prende questa decisione e per quanto tempo il sistema verrà monitorato. Le soglie devono basarsi sulle esigenze e sui segnali disponibili per l’applicazione, non su valori generici.
Un criterio di uscita utile include: installazione riproducibile, suite concordata con esito positivo, flussi critici verificati, assenza di nuovi errori non spiegati e capacità di gestire i processi in background. Registra le eccezioni note e il relativo responsabile. “I test passano” non è sufficiente se la suite non copre un’integrazione essenziale o se il team non sa quale metrica monitorare.
Distribuisci con un rollback compatibile con i dati
Se l’architettura e la piattaforma lo consentono, introduci gradualmente il nuovo runtime: prima in un ambiente controllato e poi su una parte del traffico o della capacità di esecuzione. L’esposizione graduale è una strategia di distribuzione, non la divulgazione di informazioni. Non è sempre possibile distribuire le richieste tra versioni diverse, per esempio in presenza di processi stateful o differenze nel protocollo interno; in tal caso, pianifica una transizione coordinata e verifica esplicitamente consumer e producer dei messaggi.
Prima della distribuzione, verifica che il codice precedente possa essere eseguito di nuovo in caso di errore. Il rollback non consiste soltanto nel ripristinare un’immagine: una migrazione del database, un nuovo formato di messaggio o una scrittura incompatibile possono impedire al runtime precedente di leggere i dati creati da quello nuovo. Preferisci modifiche allo schema compatibili e progressive: prima estendi lo schema, poi distribuisci codice in grado di convivere con entrambe le forme e rimuovi quella precedente quando non ci sono più consumer che ne hanno bisogno. Per ogni passaggio irreversibile, definisci una procedura di ripristino specifica e un criterio per interrompere.
Durante la distribuzione, monitora gli errori dell’applicazione e del runtime, i problemi dei worker, il ritardo delle code, le attività pianificate e i segnali di business rilevanti. Se si attiva un criterio di rollback, interrompi l’espansione della modifica e segui la procedura verificata. Conserva i log necessari a determinare la causa: tornare indietro senza diagnosticare il problema può far sì che si ripresenti al tentativo successivo.
Checklist per decidere se è tutto pronto

- Sono stati identificati il runtime e le estensioni di tutti gli ambienti e processi?
- Sono stati verificati i vincoli di Composer e gli strumenti di sviluppo?
- Analisi e test vengono eseguiti con la configurazione di destinazione?
- Sono stati testati i percorsi critici, le integrazioni, le code e le attività pianificate?
- Sono note le differenze tra CI, preproduzione e produzione?
- Sono disponibili segnali operativi, responsabili e criteri chiari per proseguire o fermarsi?
- Il codice precedente può funzionare con i dati e i messaggi che verranno prodotti dal nuovo?
- Il rollback è stato provato e si sa quali modifiche non possono essere annullate automaticamente?
La decisione di aggiornare la versione di PHP in un’applicazione esistente è più solida quando il team può rispondere a queste domande con dati concreti. Se mancano test o un inventario, il passo successivo non deve necessariamente essere una riscrittura: può consistere nel colmare prima queste lacune e ridurre l’entità della modifica. In questo modo, i potenziali problemi vengono rilevati prima di coinvolgere gli utenti e ogni decisione di distribuzione si basa su un criterio verificabile.



