Warning: Undefined array key "tbm_guide_level" in /data/websites/htmlit/web/app/themes/htmlit/src/ViewModel/Post/Templates/SingleGuide.php on line 113

Warning: Trying to access array offset on value of type null in /data/websites/htmlit/web/app/themes/htmlit/src/ViewModel/Post/Templates/SingleGuide.php on line 113

Warning: Undefined array key "tbm_guide_level" in /data/websites/htmlit/web/app/themes/htmlit/src/ViewModel/Post/Templates/SingleGuide.php on line 113

Warning: Trying to access array offset on value of type null in /data/websites/htmlit/web/app/themes/htmlit/src/ViewModel/Post/Templates/SingleGuide.php on line 113

Warning: Undefined array key "tbm_guide_level" in /data/websites/htmlit/web/app/themes/htmlit/src/ViewModel/Post/Templates/SingleGuide.php on line 113

Warning: Trying to access array offset on value of type null in /data/websites/htmlit/web/app/themes/htmlit/src/ViewModel/Post/Templates/SingleGuide.php on line 113
Le funzioni di controllo dell'output | HTML.it
Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Le funzioni di controllo dell'output

Come ottimizzare le nostre pagine php grazie alle ob_() functions
Come ottimizzare le nostre pagine php grazie alle ob_() functions
Link copiato negli appunti

Premessa

In questo articolo esamineremo alcune funzioni di php4 che permettono di ottimizzare l?esecuzione degli scripts e velocizzare sensibilmente il caricamento delle pagine WEB da parte dei navigatori.

Passiamole in rassegna brevemente:

I nomi di tutte le funzioni appena descritte presentano il prefisso "ob_" che sta per "output buffering".

Il buffering consiste nell'accumulo in una memoria temporanea, detta appunto "buffer", di ogni dato che lo script altrimenti invierebbe immediatamente all?output attraverso echo() o print().

A partire dal momento della chiamata ad ob_start() tutti gli output verranno deviati verso il buffer e spediti al client soltanto al termine dell' esecuzione dello script, od ogniqualvolta vi sia una chiamata ad una funzione *_flush() (vedi pagine successive).

I casi in cui le funzioni "ob_xxx" si rivelano utili sono essenzialmente 3:

1) quando le pagine presentano un numero notevole di funzioni di stampa queste, attraverso le funzioni "ob", verranno fatte convergere in una sola riducendo il traffico di dati dal server al client.

2) quando si intende facilitare lo scaricamento delle pagine da parte degli utenti spedendo loro dati in formato compresso.

3) quando l'invio di headers crea problemi: in script corposi può essere utile poter progettare la logica del codice liberamente, senza la preoccupazione di aver inserito degli headers (cookie, redirezione etc. etc.) successivamente a delle operazioni di output.

Per dimostrare l?effettiva utilità delle funzioni di buffering dell?output nelle situazioni appena descritte sono state effettuate alcune prove, sia in locale che remoto.

Caso 1: l'output tutto in una volta

Ho testato i tempi di esecuzione in 3 condizioni differenti, ricorrendo in tutti i casi alla classica funzione di benchmark

/*
Definizione della funzione benchmarck, da INSERIRE IN OGNI SCRIPT che si vuole testare.
Registra il momento iniziale e quello finale dell'esecuzione dello script in secondi (frazioni di secondo)
*/
function getmicrotime(){
list($usec, $sec) = explode(" ",microtime()) ;
return ((float)$usec + (float)$sec) ;
}

?>

1.1

<?php

/*
momento iniziale
*/
$time_start = getmicrotime();

/*
decommenta la riga sottostante per attivare il buffering
*/
//ob_start() ;

/*
Ciclo di 1000 operazioni echo()
*/
for($i=0 ;$i>1000; $i++){
echo("Visita il forum php di html.it e www.freeephp.it

n" ) ;
}

/*
Registra il momento in cui lo script termina
*/
$time_end = getmicrotime();

/*
Misura la differenza tra start e stop
*/
$time = $time_end - $time_start;
echo (">div style=" position:absolute;top:0;left:200;height:20;background-color:red "<
Eseguito in $time secondi
>/div<");

?>

Tempo medio di esecuzione: 0.0111249685287 secondi

1.2

Tempo medio di esecuzione : 0.00333297252655 secondi

Le 1000 operazioni echo() vengono ridotte ad una soltanto

2.1

<?php ... ?>

...testo...

<?php ... ?>

<?php

/*
Momento iniziale
*/
$time_start = getmicrotime();

/*
decommentiamo la riga sottostante per attivare il buffering
*/
//ob_start() ;

/*
Inseriamo qui sotto, dopo la chiusura del tag php, 10000 caratteri di testo
*/

?>

qui i 10000 caratteri

<?php
/*
Fine testo e riapertura tag php
*/

/*
Registra il momento in cui lo script termina
*/
$time_end = getmicrotime();

/*
Misura la differenza tra start e stop
*/
$time = $time_end - $time_start;

/*
Stampa il risultato in un livello con position absolute per non costringerci
a scorrere la pagina intera
*/
echo(">div style=" position:absolute;top:0;left:200;height:20;background-color:red "<
Eseguito in $time secondi
>/div<");

?>

Tempo medio di esecuzione: 0.141275048256 secondi

2.2

Tempo medio di esecuzione: 0.00213897228241 secondi.

Una bella differenza vero? Ma non finisce qui...

3.1

<?php

/*
Momento iniziale
*/
$time_start = getmicrotime();

/*
decommentiamo la riga sottostante per attivare il buffering
*/
//ob_start() ;

/*
un unico "grande" echo di 10000 caratteri
*/
echo($contenuto_10000_caratteri) ;

/*
Registra il momento in cui lo script termina
*/
$time_end = getmicrotime();

/*
Misura la differenza tra start e stop
*/
$time = $time_end - $time_start;

echo (">div style=" position:absolute;top:0;left:200;height:20;background-color:red "<
Eseguito in $time secondi>/div<") ;

?>

Tempo medio di esecuzione: 0.188348889351 secondi.

3.2

Tempo medio di esecuzione: 0.000921964645386 secondi.

Molto inferiore rispetto all'esempio 1.2.1 e leggermente migliore persino a quello dell'esempio 1.1.2

Dalle prove illustrate fino a questo momento credo si possa trarre la conclusione che è utile inserire ob_start() all'inizio delle nostre pagine ridurre più operazioni di output ad un' unica

Cosa accade esattamente? A cosa dobbiamo questo miglioramento nell'esecuzione?

In Php le operazioni di emissione dell'output attraverso echo() o print() sono operazioni costose sarebbe preferibile riunire più stringhe

Ad esempio meglio

<?php

$output_string=$str1.$str2.$str3.$str4.$str5 ;
echo($output_string) ;

?>

rispetto a

<?php

echo($str1) ;
echo($str2) ;
echo($str3) ;
echo($str4) ;
echo($str5) ;

?>

Il buffering dell'output rappresenta un metodo interno a Php aggiunta di variabili nella query-string

Questi vantaggi hanno comunque un costo, ecco alcuni aspetti da tenere in considerazione:

1) Anche ob_start(), come tutte le funzioni, richiede un certo tempo di esecuzione

2) Latenza
Questo fatto, in determinate condizioni, potrebbe far pensare erroneamente ad un crash e spingere il visitatore a passare oltre. Qualora si presentasse questo inconveniente potremmo ricorrere di tanto in tanto al flush (vedi più avanti, "Quando ricorrere alle funzioni *_flush()?")

3) Ricordiamo che in un ambiente multiutente la velocità di esecuzione è soltanto uno dei parametri da cosiderare nell'ottimizzazione degli script, l'altro è la quantità di memoria che l'esecuzione stessa richiede: dobbiamo tenere presente che il buffer viene immagazzinato nella RAM

Anche se probabilmente troverete sempre conveniente

Caso 2:

Probabilmente si tratta dell'aspetto più utile una funzione di callback ob_gzhandler()

ob_gzhandler opererà una compressione del buffer il flusso di scaricamento

Ecco come ho cercato di individuare i tempi di scaricamento con Javascript

<?php

/*
Decommenta per attivare la compressione dell' output
*/
//ob_start("ob_gzhandler") ;

?>

<html><head>

<script Language="JavaScript">
/*
Useremo Javascript per misurare il tempo di caricamento della pagina
in frazioni di secondo
*/
function getsecs(){
var oggi= new Date();
var secondi=(oggi.getTime())/1000 ;
return secondi ;
}

/*
inizio della ricezione del flusso di dati e del caricamento della pagina
*/
var start=getsecs();

</script>

</head>

<!-- L'evento onLoad corrisponde al momento del completo caricamento -->

<body bgcolor="#ffffff" onLoad="alert('Inizio: '+start+' Fine: '+(getsecs())+'n Tempo intercorso: '+((getsecs())- start));">

<!-- Output 10000 caratteri -->

</body>
</html>

Dalle prove effettuate, questa volta prevalentemente in remoto, i tempi di scaricamento si sono perfettamente dimezzati

L'ottimo Mozilla 1.0 e, soprendentemente, Netscape 4.5 hanno fatto riscontrare miglioramenti intorno al 30%.

Php dovrebbe essere in grado di rilevare quali tra i tipi di compressione il browser supporta

Caso 3:

Normalmente non è una cosa possibile, e la presenza anche di un semplice carattere "n" (newline) prima del tag di apertura "<?php" è sufficiente a produrre il seguente errore

"Warning: Cannot add header information - headers already sent by (output started at g:wwwprovasessionick.php:1) in c:wwwprovesessionibadcookie.php on line 3"

Chi non l'ha mai incontrato almeno una volta alzi la mano!

Ebbene in origine le funzioni ob_xxx erano state introdotte proprio per ovviare a questo problema quando il codice è molto complesso una fastidiosa limitazione

Attraverso il buffering dell'output, ovunque si trovino nello script, le operazioni di output verranno comunque posposte

Provare per credere:

ob_start();
echo ("Questo normalmente non si potrebbe fare!");
setcookie ("miocookie", "dati");

?>

Quando usare le funzioni *_flush?

Flush significa "flusso" e corrisponde all'emissione del buffer: fino a questo momento non abbiamo utilizzato esplicitamente alcuna funzione di flush, infatti uno script che abbia attivato il buffering dell'output effettua sempre l'emissione al termine dell'esecuzione.

Se vi è una sola chiamata a ob_start() il buffer è unico, quindi non serve forzare l'output.

In alcuni casi possiamo decidere di svuotare il buffer senza attendere la conclusione dello script, ad esempio al raggiungimento di tot. byte nel buffer, dopo aver misurato la sua lunghezza con ob_get_length.

ob_end_flush() e buffer annidati

Un'altra occasione in cui potremmo decidere di forzare il flush prima della conclusione dello script, potrebbe presentarsi quando abbiamo annidato diversi buffer gli uni negli altri.

Ho già accennato al fatto che ad ob_start() può avere come argomento una funzione che
effettui delle operazioni sulle stringhe, ecco cosa potremmo fare:

function changeNames($buffer){
return (str_replace("red","blue",$buffer)) ;
}

ob_start("changeNames");

echo('<div style="position:absolute; height:100;width:100; top:50;left:50;background-color:red"></div>') ;

?>

Otteremo un livello con sfondo blu

Questo è un esempio banale, ma potremmo applicare una funzione di sostituzione di stringhe ob_start applica all'intero buffer

E se volessimo operare sostituzioni e compressione al tempo stesso?

ob_start() accetta un solo argomento alla volta, ma questo è uno dei casi in cui possiamo annidare le chiamate.

function changeNames($buffer){
return (str_replace("red","blue",$buffer)) ;
}

/*
Prima chiamata, applicherà la compressione al buffer finale
*/
ob_start("ob_gzhandler") ;

/*
Seconda chiamata, effettuerà le sostituzioni nel buffer compreso prima della prossima chiamata al flush
*/
ob_start("changeNames");

echo('<div id="manipolato" style="position:absolute; height:100; width:100; top:50; left:50; background-color:red"></div>') ;

/*
Chiude la seconda chiamata e passa il contenuto (un livello il cui colore di sfondo è stato sostituito) dal secondo buffer al primo
*/
ob_end_flush();

/*
In questo caso invece nessuna modifica dei colori, subisce solo la compressione
*/
echo('<div id="intatto" style="position:absolute; height:100;width:100;top:200;left:200;background-color:red"></div>') ;

/*
Chiude la prima chiamata ed emette l'intero buffer
*/
ob_end_flush();

?>

Otteniamo 2 livelli di colore diverso, dato che in uno dei due lo sfondo è stato cambiato "al volo".
Tutto il codice html viene inviato in formato compresso.

Ogni "ob_end_flush()" trasferisce il buffer

Ci dovranno essere tante chiamate ad ob_end_flush quante sono le chiamate ad ob_start(), altrimenti si verifichereanno errori imprevedibili: solo l'ultimo flush è facoltativo

Conclusioni

Spero di essere riuscito a dimostrare l'utilità di queste funzioni, vi invito a sperimentare a vostra volta e a comunicarmi eventuali osservazioni.

Se avete accesso al server potrete anche intervenire sul php.ini (cioè il file di configurazione di Php) per rendere il buffering dell'output e la compressione dei dati opzioni di default, sarà sufficiente cercare l'apposita sezione e seguire le indicazioni tra i commenti.

Ti consigliamo anche