Jak na mnohonásobné bufferování, aneb jak správně používat ob_start()
V tomto článku se dozvíte více o funkci ob_start, ob_get_contents, ob_flush, ob_end_clean apod., hlavně o bufferovacích mechanismech v php.
O bufferovacích funkcích už se tady něco napsalo například v článku o zobrazování průběhu časově náročných operací nebo v článku o použití šablon pro emaily odesílané pomocí php. Tento článek se jimi bude zabývat více a snad pomůže ujasnit některé úskalí těchto funkcí.
Bufferovací funkce dovolují programátorovi kontrolovat výstup na obrazovku, např. to co by se normálně vypsalo na obrazovku se nejprve načte do proměnné, pak můžeme celý výstup ještě upravit a teprve poté zobrazit na obrazovce, poslat mailem, uložit do souboru apod.
Jednou z výhod bufferovacích funkcí je, že neovlivňují odeslané hlavičky (header), ty nesmí být odeslány po jakémkoli výstupu na obrazovku, např. výsledek funkce echo nebo vypsaný html kód. Stejně tak nemůže být použito funkce pro nastavení cookies (setcookie).
Nejdůležitější je funkce ob_start(), která zapne kontrolu výstupu na obrazovku, tedy od volání této funkce se na obrazovce nic nezobrazí.
Následující ukázka je upravená verze příkladu z manuálu k php, ukazuje využití ob_start a nastavení parametru, který určuje volanou funkci po skončení bufferovacího bloku.
- <?
- function callback($buffer) {
- return (str_replace("apples", "oranges", $buffer));
- }
- ob_start("callback");
- ?>
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <title>Příklad k funkci ob_start()</title>
- </head>
- <body>
- <p>It's like comparing apples to oranges.</p>
- </body>
- </html>
- <?
- ob_end_flush();
- ?>
Vše co je uzavřeno mezi příkazy ob_start a ob_end_flush je odesláno jako hodnota proměnné $buffer a předáno funkci callback, to probíhá nastavením ob_start("callback");. V případě, že chceme volat funkci nějakého objektu, nastavení pak vypadá takto ob_start(array($this, 'callback'));, v předchozím přikladu volání ob_start vidíme jak volat funkci uvnitř aktuální instance třídy.
Další důležité funkce jsou ty, pro ukončení bufferovacího bloku. Např. zmíněná ob_end_flush(), ta ukončí bufferovací blok a celý obsah zobrazí na obrazovce, o úspěšném ukončení bloku nás informuje hodnotou true nebo false. Ukončit blok můžeme i funkcí ob_end_clean(), narozdíl od předchozí funkce, tahle smaže obsah zásobníku (bufferu).
Pro pouhé smazání zásobníku slouží funkce ob_clean(). Pro vypsání dosud načteného zásobníku slouží ob_flush a flush().
Následující ukázka nabízí příklad několikanásobného bufferování.
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <title>Příklad k článku: Jak na mnohonásobné bufferování, aneb jak správně používat ob_start()</title>
- </head>
- <body>
- <h1>Příklad k článku: Jak na mnohonásobné bufferování, aneb jak správně používat ob_start()</h1>
- <?
- ob_start();
- echo "Start buffer block 1.<br/>";
- ob_start();
- echo "Start buffer block 2.<br/>Level:".ob_get_level()."<br/>";
- $bb1 = ob_get_contents();
- ob_end_flush();
- echo "Write to buffer block 1.<br/>";
- $bb2 = ob_get_contents();
- ob_end_clean();
- ?>
- <p>End of all buffer blocks. And still writting.</p>
- <h2>Show buffer block 1.</h2>
- <p><?=$bb1;?></p>
- <h2>Show buffer block 2.</h2>
- <p><?=$bb2;?></p>
- </body>
- </html>
Funkce, která načte do proměnné obsah aktuálního zásobníku jako text (string) je ob_get_contents(). Funkce ob_get_clean() pak spojuje volání funkcí ob_get_contents() a ob_end_clean(), tedy načte obsah zásobníku do proměnné a pak zásobník vyprázdní.
Funkce ob_get_flush() je podobná funkci ob_end_flush(), ale navíc vrátí obsah zásobníku do proměnné.
Funkce ob_get_length() vrátí délku bufferu, tedy délku stringu, obdoba strlen().
Funkce ob_get_level() vrací velikost zanoření jednotlivých bufferovacích bloků uvnitř sebe.
Funkce ob_get_status() vrací pole s aktuálním stavem všech aktivních běžících bufferovacích bloků.
Funkce ob_gzhandler() se používá jako callback funkce v ob_start("ob_gzhandler") a provede gzip kompresi zásobníku.
Funkce ob_implicit_flush() zapíná a vypíná vypisování zásobníku po každém výstupu, tedy jedná se o automatické volání funkce flush().
Funkce ob_list_handlers() naplní pole seznamem všech aktivních bufferovacích bloků.
Funkce pro práci s proměnnými v URL jsou output_add_rewrite_var() a output_reset_rewrite_vars(), tyto funkce doplní při každém kliknutí parametr a jeho hodnotu do URL, stejně tak přidají skryté pole do formuláře, pro lepší pochopení pročtěte manuál.
To je vše co potřebujete vědět pro práci s bufferovacími funkcemi.
komentáře
RSS Komentáře
pro tento článek o bufferování mně byla inspirací právě naše rozepře na diskuse.jakpsatweb.cz :), osobně používám bufferování pro např. šablony mailu nebo generování obfus javascriptu a css, případně dalších kešovaných stránek
připomenu naši rozepři: argumentoval jsem tím, že bufferování je zbytečně náročné, ale omlouvám se a nezamyslel jsem se před tím výrokem, dle mého není náročné a náročnost je zanedbatelná, vždyt jde jen o alokování paměti v rozsahu textu poslaného na obrazovku, to je opravdu zanedbatelné, pokud si někdo myslí opak ať mi oponuje
vzhledem k tomu, že průměrná stránka nebude mít víc než 50kb tak to je celkem přijatelná alokace paměti ne?
Tak to se muzu omluvit tez, jelikoz jsem vyjel bez toho aniz bych si to poradne overil, coz jsem neucinil dodnes. Ziju v domneni ze je to rychle a neprilis zatezujici, a cerpam z toho, ze jak na firemnich tak soukromych webech pouzivam podobnou sablonu kdy do bufferu natahnu cely web a je jedno jak je velky a je to proste rychle :)
Bude clanek o tabulkach? Tesim se na to jak maly kluk :) ( ukladani dat a vypis dat ⇒ tabulky na nhlpro.cz , tesim se ze poznam novy zpusob )
Hlavní nevýhoda output bufferingu (pokud je přes celou stránku a bez druhého parametru funkce ob_start) je ta, že stránka se do prohlížeče začne posílat až v momentě, kdy se na serveru celá sestaví. Pro uživatele to je nepříjemné v tom, že první kousek stránky vidí až v momentě, kdy se mu už posílá celá.
Lepší uživatelský dojem se navodí tím, když se stránka posílá průběžně.



Pekny clanek, osobne pouzivam bufferovani pro to abych mohl menit titulek stranky pote co si nekde na konci stranky vytahnu neco dynamicky z databaze.
Jak je to s narocnosti, kdyz se takto do bufferu natahuje cela stranka?