PHP 4.0 è uscito il 22 maggio 2000, due anni dopo la versione 3, e la differenza che si misura sta nel motore di esecuzione: il nuovo Zend Engine, scritto da Zeev Suraski e Andi Gutmans, separa la compilazione di uno script dalla sua esecuzione. In PHP 3 le due fasi erano intrecciate nello stesso albero di parsing; adesso lo script viene prima tradotto in opcode intermedio e poi eseguito su quegli opcode. Per chi scrive applicazioni più grandi di una pagina di benvenuto, questa separazione è la prima cosa da capire.
Contesto
Ho iniziato a usare PHP 3 per generare pagine a partire da query SQL, e il limite si sentiva su due fronti: le prestazioni quando un template conteneva molti cicli, e l’assenza di una gestione dello stato che non passasse da hack manuali sui cookie. PHP 3 bastava per poche righe di script dentro un documento HTML, ma reggeva meno appena la logica cresceva e il file diventava un miscuglio di marcatura e codice difficile da seguire.
La documentazione del progetto descrive PHP come un linguaggio pensato per il web e incorporabile direttamente nell’HTML, e qui sta anche il suo tratto architetturale principale: non un server applicativo a sé, ma un interprete che vive dentro il ciclo richiesta-risposta di un web server.
Architettura: cosa fa il motore a ogni richiesta
Il modello di esecuzione è legato strettamente a HTTP. Per ogni richiesta in arrivo l’interprete:
- carica il file
.phprichiesto; - lo compila in opcode (con il nuovo Zend Engine questa è una fase distinta);
- esegue gli opcode e produce l’output;
- invia il risultato al client e libera la memoria allocata.
Al passo 4 lo stato del processo viene azzerato. Niente di quanto si è accumulato durante la richiesta sopravvive alla richiesta stessa. Lo chiamo modello shared-nothing perché due richieste consecutive non condividono variabili, oggetti o connessioni, se non si usa un meccanismo esplicito di persistenza.
Con il modulo mod_php per Apache l’interprete gira dentro il processo del web server, e non come processo CGI separato avviato a ogni richiesta. La differenza si tocca con mano: il CGI tradizionale fa il fork di un interprete nuovo a ogni richiesta, mentre mod_php tiene l’interprete già caricato dentro Apache. Su un sito con traffico vero, risparmiare quel fork è la voce che pesa di più sul tempo di risposta.
Il punto critico: la compilazione ripetuta
La separazione tra parsing ed esecuzione del Zend Engine è un guadagno reale, ma porta con sé un problema immediato. Gli opcode prodotti al passo 2 vengono buttati al passo 4 insieme al resto della memoria. La richiesta successiva allo stesso file ricompila lo script da capo, anche quando il sorgente non è cambiato.
Per un file piccolo il costo è trascurabile. Per un’applicazione con decine di file inclusi, il tempo di compilazione si paga su ogni richiesta e diventa una frazione misurabile della latenza. La separazione tra opcode ed esecuzione apre la porta a una cache degli opcode — tenere il prodotto del passo 2 e riusarlo finché il sorgente non cambia — ma nella distribuzione standard di PHP 4.0 questa cache non c’è. È una strada che il nuovo motore rende percorribile, non una funzione che arriva installando il pacchetto.
Gestione dello stato
PHP 4 porta nel nucleo del linguaggio la gestione delle sessioni, che in PHP 3 richiedeva una libreria esterna. Una sessione lega un identificativo (in un cookie o nella query string) a un insieme di dati lato server, e ricostruisce quei dati a ogni richiesta dello stesso client. È il modo previsto per dare continuità a un protocollo, HTTP, che continuità non ne ha: ogni richiesta arriva senza memoria della precedente.
Accanto alle sessioni, la versione 4 espone l’output buffering: l’output dello script si può trattenere in un buffer invece di partire subito verso il client. Serve a un caso pratico che torna spesso — cambiare gli header HTTP dopo aver già generato parte del corpo, cosa che senza buffer è impossibile, perché in HTTP gli header precedono il corpo e una volta inviati non si ritirano.
Lo stack e le sue parti
PHP occupa il livello applicativo di una combinazione che gira interamente su software con sorgenti disponibili: Linux come sistema operativo, Apache come web server, un database relazionale come MySQL o PostgreSQL, PHP come linguaggio. Le estensioni database della versione 4 coprono MySQL, PostgreSQL, Oracle e l’accesso generico via ODBC, quindi la scelta del DBMS non è legata a un solo prodotto.
Il vantaggio operativo di questa combinazione è la riproducibilità: ogni pezzo si scarica, si compila e si configura senza licenze d’uso, e questo abbassa la soglia per chi vuole capire come funziona ciascun livello leggendone il sorgente.
Limiti
Tre cose restano scoperte e vanno tenute presenti prima di costruirci sopra.
La prima è la cache opcode che manca nel pacchetto standard, già detta: il guadagno del motore separato resta in parte teorico finché ogni richiesta ricompila.
La seconda è la condivisione delle risorse costose. Il modello shared-nothing semplifica il ragionamento sulle richieste concorrenti, ma vuol dire anche che ogni richiesta apre e chiude la propria connessione al database, a meno di usare le connessioni persistenti — che a loro volta vanno dimensionate con cura rispetto al numero di processi Apache, perché ogni processo può tenere aperta la sua connessione e il totale satura in fretta i limiti del server SQL.
La terza è il linguaggio stesso: l’oggetto in PHP 4 esiste, ma è poco più di un array con funzioni associate, senza incapsulamento reale e senza distinzione tra membri pubblici e privati. Per una libreria condivisa fra più progetti questo pesa, e va saputo prima e non dopo aver scelto una struttura a oggetti.
Resta da vedere quanto di tutto questo verrà colmato dalle estensioni di terze parti già in circolazione e quanto invece chiederà una nuova versione del motore.
https://www.php.net/ https://www.php.net/manual/en/history.php.php https://www.php.net/manual/en/getting-started.php https://httpd.apache.org/ https://www.noze.it/insights/php4-open-source/
Immagine di copertina: Zeev Suraski, tra i principali autori di PHP, mentre parla a una conferenza del 2005 — foto di Christophe Gesché, CC BY-SA 2.0 — https://commons.wikimedia.org/wiki/File:Zeev_Suraski_2005.jpg