A "parità di peso", la creazione di una pagina Web attraverso uno script PHP è necessariamente più lenta del semplice caricamento di una pagina HTML nativa, questo è dovuto al fatto che un output generato tramite PHP richiede un numero maggiore di elaborazioni e conseguentemente un superiore impiego di risorse.
Nel caso del caricamento di una comune pagina HTML "statica" (cioè non prodotta dinamicamente sulla base dell'input inviato) abbiamo i seguenti passaggi:
- Il client invia una richiesta al server, per esempio sotto forma di URL digitata tramite browser;
- Il Web server effettua un controllo per verificare se la risorsa richiesta esiste;
- Se la risorsa richiesta è presente allora questa viene inviata come risposta al client sotto forma di pagina HTML.
Vediamo ora quali passaggi sono necessari per la generazione di una pagina PHP:
- Invio dell'input da parte del client;
- Controllo da parte del Web server ed interpretazione della richiesta;
- Chiamata all'esecutore PHP per l'elaborazione dell'input;
- Restituzione dell'output.
Detto in parole molto semplici, nel caso in cui una richiesta è diretta verso una "pagina statica" questa viene restituita così com'è, non è quindi il prodotto di alcuna elaborazione, cosa che invece accade nel caso di un documento HTML generato tramite uno script PHP.
Quando richiediamo ad un Web server una pagina HTML nativa è un po' come se andassimo a cercare un file all'interno di un disco rigido; quando invece richiediamo una pagina prodotta tramite PHP è come se utilizzassimo un programma per produrla.
Chiaramente, tra le due procedure descritte la seconda è molto più dispendiosa per il sistema in termini di risorse.
Questo dispendio si traduce in tempi di attesa più o meno lunghi per gli utenti, diventa quindi necessario concepire script PHP che riducano il più possibile il carico di lavoro sul Web server; per far questo esistono degli accorgimenti da adottare in sede di sviluppo che possono aiutarci a rendere più performanti i nostri codici. Li vediamo nella prossima pagina, partendo da alcune regole di base.
Regole di base per script PHP performanti
L'estenuante ricerca della performance migliore può portare alla cosiddetta "sindrome da benchmark" (in verità più diffusa presso i programmatori che tra gli sviluppatori di siti Web), per la quale la conquista di una frazione di secondo diventa un risultato importante anche se costituisce un vantaggio assolutamente impercettibile per l'utente finale.
A mitigare la "sindrome da benchmark" vi è il fatto che al giorno d'oggi le macchine server godono di configurazioni elevate in grado di gestire meglio le risorse anche in situazioni critiche caratterizzate da alto traffico e numerose richieste; nello stesso tempo è vero anche che il numero delle persone che usufruisco del Web è sempre in aumento e che quindi il migliorato parco hardware e software deve fare i conti con utenze sempre più vaste.
Per evitare questo tipo di ossessioni è bene cominciare da subito applicando alle proprie sessioni di sviluppo delle regole di base grazie alle quali si otterranno immediatamente dei migliori risultati in termini di performance.
Pensiamo per esempio alla produzione degli output tramite i costrutti echo
e print
, forse molti non sanno che dal lato della velocità di esecuzione il primo è sempre preferibile; parliamo di differenze minime, ma se consideriamo che questi due costrutti presiedono praticamente alla generazione di tutti gli output la scelta tra uno di essi può alla fine risultare determinante.
Esiste un motivo che spiega in parte il motivo per cui echo
viene eseguito più velocemente rispetto a print
: echo
non restituisce alcun valore mentre print
assume un comportamento per molti versi simile a quello di una funzione, restituendo sempre 1.
Rimaniamo sempre nell'ambito della produzione degli output introducendo un nuovo argomento, quello relativo agli apici e ai doppi apici; quali preferire in un discorso orientato alle performance?
Ecco due differenti approcci alla delimitazione delle stringhe:
$nome = 'Mario'; $cognome = 'Rossi'; #stringa delimitata da apici echo 'Mi chiamo: '.$nome.' '.$cognome; #stringa delimitata da doppi apici echo "Mi chiamo: $nome $cognome";
Gli sviluppatori più attenti suggeriscono giustamente di utilizzare un sistema coerente di delimitazione delle stringhe e delle variabili, questo per una questione di ordine del listato; si tratta di una modalità particolarmente adatta per la scrittura di tutorial nei quali un utilizzo promiscuo della delimitazione potrebbe generare confusione in chi legge.
Si tenga comunque conto del fatto che a livello di performance sarebbe preferibile delimitare le stringhe pure con gli apici singoli, mentre sarebbe meglio utilizzare i doppi apici quando si devono inglobare variabili all'interno di stringhe.
PHP infatti non si aspetta di trovare variabili all'interno degli apici singoli, non le ricerca ed esegue l'output più velocemente.
Un utilizzo corretto dei caratteri di delimitazione svolge una funzione importante in quanto "aiuta" PHP in fase di interpretazione del codice, in pratico con dei semplici apici eseguiamo del lavoro che diversamente sarebbe a carico dell'interprete; un caso classico è quello relativo ai valori di array derivanti da query di selezione su database: tra $row'nome']
e $row[nome]
è preferibile la prima forma in quanto immediatamente comprensibile per l'interprete nonché sintatticamente più corretta.
Un discorso molto simile è quello relativo alla generazione in output di codice HTML puro: meglio produrlo tramite PHP o digitare il markup al di fuori dei tag di delimitazione del linguaggio server side?
In questo caso sono a disposizione differenti metodologie:
<p> <?php echo 'Mi chiamo Mario Rossi'; ?> </p> <?php echo '<p>Mi chiamo Mario Rossi</p>'; ?> <?php echo '<p>'; echo 'Mi chiamo Mario Rossi; echo '</p>'; ?>
Posto che è sempre buona norma separare quanto più possibile il codice dell'applicazione da quello relativo alla presentazione, la soluzione migliore appare quella di non produrre l'HTML tramite PHP; il motivo lo abbiamo spiegato all'inizio di questa trattazione: l'HTML non necessita di particolari elaborazioni da parte del Webserver ma viene proposto così com'è, senza richiedere alcuna esecuzione, per poi essere interpretato dal browser del client.
Un altro discorso importante è quello relativo all'utilizzo dei cicli ed in particolare alla loro condizione di terminazione (massimo valore d'incremento); molto spesso questa condizione non viene rappresentata attraverso una semplice variabile ma tramite un argomento passato ad una funzione, come accade nell'esempio seguente:
for ($i = 0; $i <= count($array); ++$i) { //istruzione }
Sintatticamente non vi è nulla da eccepire, ma a livello di performance incontriamo un piccolo problema dato che la funzione verrà rieseguita ad ogni iterazione del ciclo, sarebbe quindi buona norma che i valori relativi alle condizioni di terminazione venissero calcolati prima di essere utilizzati all'interno dei loop.
Prima di concludere questa parte della trattazione è bene fare un piccolo riferimento alle funzioni: PHP conta migliaia di funzioni native per gli usi più disparati, prima di avventurarci nella creazione di una funzione personalizzata è quindi sempre utile consultare il manuale ufficiale di PHP e informarsi se per caso non esistano costrutti predefiniti in grado di svolgere gli stessi compiti in modo più veloce.
Performance e OOP in PHP
La programmazione orientata agli oggetti, il cui pieno supporto è stato introdotto in PHP con la versione 5, rappresenta una grande comodità per lo sviluppatore in quanto fornisce un'alternativa più completa all'approccio procedurale; ma l'utilizzo dell'OOP contribuisce a rendere gli script più performanti? La risposta corretta è "non sempre", anzi, in alcuni casi pur utilizzando la sintassi in modo corretto otteniamo risultati che possono essere meno performanti rispetto a quelli possibili attraverso l'approccio procedurale.
Il caso classico di sovra-impiego delle risorse nell'OOP è quello relativo all'overhead: con questo termine vengono definite le risorse in sovrappiù (e quindi accessorie), rispetto a quelle strettamente necessarie per svolgere un determinato compito in seguito all'introduzione di un metodo o di un processo.
L'overhead richiesto per la chiamata di un metodo in un linguaggio di programmazione orientato agli oggetti è sempre maggiore rispetto a quello necessario per richiamare un sottoprogramma di un linguaggio procedurale; ciò accade per via delle risorse richieste dell'overriding dei metodi.
L'overriding si ottiene quando si desidera ridefinire un metodo appartenente ad una classe principale ma all'interno di una sottoclasse, in questo modo sarà possibile generare versioni più specializzate dei metodi; non vi è nulla di scorretto, ma sarà necessario tenere conto del fatto che ciascun metodo e ciascuna chiamata ad un oggetto richiedono un'ingente quantità di risorse.
Esistono però alcune semplici regole che possono aiutarci a migliorare le performance delle nostre applicazioni anche se realizzate tramite l'OOP:
- non richiamare funzioni vuote se non strettamente necessario;
- non suddividere esageratamente i metodi ed eventualmente eliminare le porzioni di listato inutilizzate;
- per loro natura i codici dei metodi sono generalmente divisibili, sarà quindi possibile fare in un secondo momento quello che ora non è strettamente necessario;
- utilizzare gli array per la strutturazione dei dati in luogo delle classi quando possibile;
- utilizzare se possibile i metodi relativi alle classi derivate perché più veloci di quelli delle superclassi;
- dichiarare i metodi static quando possibile (in quanto sono molto più veloci);
- evitare quando possibile i cosiddetti "metodi magici" come
__get
o__set
per l'overloading o__autoload
per l'evocazione delle classi.
Inoltre, almeno per il test di applicazioni complesse, è sempre bene dotarsi di uno strumento avanzato per eseguire il debug degli script; per chi non ne avesse ancora scelto uno o per chi non lo conoscesse consigliamo l'utilizzo di Xdebug, un'estensione di PHP libera e gratuita tra le più utilizzate dagli sviluppatori.
Conclusioni
In questa trattazione abbiamo affrontato il discorso riguardante il miglioramento delle prestazioni degli script PHP. Sono state analizzate le problematiche relative al corretto utilizzo di sintassi, costrutti e funzioni sia nella programmazione procedurale che in quella orientata agli oggetti, sono state poi proposte alcune possibili soluzioni per il miglioramento delle performance tenendo conto in particolare delle esigenze dei lettori alle prime armi.