Jakie jest zastosowanie ob_start () w php?


298

Jest ob_start()stosowany do output bufferingtak że nagłówki nie są buforowane i wysyłane do przeglądarki? Czy mam tu sens? Jeśli nie, to dlaczego powinniśmy skorzystać ob_start()?

Odpowiedzi:


481

Pomyśl o ob_start()powiedzeniu: „Zacznij zapamiętywać wszystko, co normalnie byłoby generowane, ale jeszcze nie rób nic z tym”.

Na przykład:

ob_start();
echo("Hello there!"); //would normally get printed to the screen/output to browser
$output = ob_get_contents();
ob_end_clean();

Istnieją dwie inne funkcje, z którymi zwykle się łączysz: ob_get_contents()co w zasadzie daje ci to, co zostało „zapisane” w buforze od momentu włączenia ob_start(), a następnie ob_end_clean()lub ob_flush(), które albo zatrzymuje zapisywanie rzeczy i odrzuca wszystko, co zostało zapisane, lub przestaje zapisywać i wysyła to wszystko jednocześnie.


55
Świetne wyjaśnienie. Chciałbym pójść o krok dalej i wymienić ob_get_contents()się ob_get_clean()i usunąć ob_end_clean()gdyż ob_get_clean()zasadniczo spełnia obie te funkcje. Odniesienie: php.net/manual/en/function.ob-get-clean.php (PHP 4> = 4.3.0, PHP 5)
Con Antonakos

Zakładam, że buforowanie danych wyjściowych musi być włączone w kolejności plików .ini, aby wywoływać ob_start();Czy to jest prawidłowe? Co się stanie, jeśli nie zostanie włączone?
Kevin Wheeler

5
@Riley Dutton Nie mówisz, dlaczego używana jest funkcja ob_start ()
Vishnu R Nair

Miałem ten sam problem, po naprawieniu mojego kodu ob_end_cleandziała jak urok! Dzięki @Riley Dutton
Martins

160

Używam tego, więc mogę wyjść z PHP z dużą ilością HTML, ale nie mogę go renderować. Oszczędza mi to przechowywania go jako łańcucha, który wyłącza kodowanie kolorami IDE.

<?php
ob_start();
?>
<div>
    <span>text</span>
    <a href="#">link</a>
</div>
<?php
$content = ob_get_clean();
?>

Zamiast:

<?php
$content = '<div>
    <span>text</span>
    <a href="#">link</a>
</div>';
?>

1
Czy można to wykorzystać jako sposób na posiadanie wielu stron HTML w jednym PHP i wywoływanie ich przez GET?
joshkrz

1
Chyba tak, ale to nie brzmi jak dobry pomysł. Lepiej byłoby załadować je z oddzielnych szablonów.
JD Isaacks

1
Zauważ, że ta technika używa ob_get_clean(), a nie ob_end_clean()
Blazemonger

11
Nigdy o tym nie myślałem, to niesamowicie przyjazny dla IDE sposób rozwoju! Co więcej, eliminuje to potrzebę używania JavaScript lub HTML jako łańcucha znaków w moim PHP, ciągłego uciekania się od \ "itd., Co jest denerwujące
J-Dizzle,

1
Twój obraz daje wyraźny obraz korzyści płynących z używania ob_start.
klewis

86

Przyjęta tutaj odpowiedź opisuje, co ob_start()nie - dlaczego nie jest używana (jakie było zadane pytanie).

Jak stwierdzono w innym miejscu, ob_start()tworzy bufor, do którego zapisywane są dane wyjściowe.

Ale nikt nie wspomniał, że w PHP można układać wiele buforów. Zobacz ob_get_level ().

Jeśli chodzi o to, dlaczego ....

  1. Wysyłanie HTML do przeglądarki w większych fragmentach zapewnia większą wydajność dzięki zmniejszeniu obciążenia sieci.

  2. Przekazywanie danych z PHP w większych porcjach zapewnia zwiększenie wydajności i pojemności poprzez zmniejszenie liczby wymaganych przełączników kontekstu

  3. Przekazywanie większych porcji danych do mod_gzip / mod_deflate daje korzyść w zakresie wydajności, ponieważ kompresja może być bardziej wydajna.

  4. buforowanie danych wyjściowych oznacza, że ​​nadal możesz manipulować nagłówkami HTTP później w kodzie

  5. jawne opróżnienie bufora po wypisaniu [head] .... [/ head] może pozwolić przeglądarce rozpocząć zbieranie innych zasobów dla strony przed zakończeniem strumienia HTML.

  6. Przechwytywanie danych wyjściowych w buforze oznacza, że ​​można je przekierować do innych funkcji, takich jak poczta e-mail, lub skopiować do pliku jako buforowaną reprezentację treści


29

Masz to do tyłu. ob_start nie buforuje nagłówków, buforuje zawartość. Używanie ob_startpozwala przechowywać zawartość w buforze po stronie serwera, dopóki nie będziesz gotowy do jej wyświetlenia.

Jest to powszechnie stosowane, aby strony mogły wysyłać nagłówki „po”, że „wysłały” już trochę treści (tj. Decydują się na przekierowanie w połowie renderowania strony).


3
+1 Ja też byłem zdezorientowany co do faktycznego użycia funkcji. Twoja odpowiedź dotycząca jego użycia podczas „przekierowania” przypomniała mi o wszystkich czasach, w których miałem błąd „Nagłówki już wysłane”. Dzięki
klep

13

Wolę:

ob_start();
echo("Hello there!");
$output = ob_get_clean(); //Get current buffer contents and delete current output buffer

8

ma to na celu dalsze wyjaśnienie odpowiedzi JD Isaaksa ...

Problem, z którym często się spotykasz, polega na tym, że używasz php do generowania html z wielu różnych źródeł php, a źródła te często, z jakiegokolwiek powodu, generują na różne sposoby.

Czasami masz dosłowną zawartość HTML, którą chcesz bezpośrednio wyświetlić w przeglądarce; innym razem dane wyjściowe są tworzone dynamicznie (po stronie serwera).

Treść dynamiczna zawsze będzie (?) Ciągiem. Teraz musisz połączyć ten zhitalizowany dynamiczny HTML z dowolnym dosłownym, bezpośrednim HTML-em ... w jedną znaczącą strukturę węzłów HTML.

Zwykle zmusza to programistę do zawinięcia całej treści bezpośrednio do wyświetlania w łańcuch (jak omawiał JD Isaak), aby można ją było poprawnie dostarczyć / wstawić w połączeniu z dynamicznym HTML-em ... nawet jeśli tak naprawdę nie chcę to zapakowane.

Ale stosując metody ob _ ## można uniknąć bałaganu owijania łańcuchów. Zamiast tego dosłowna zawartość jest wyprowadzana do bufora. Następnie w jednym prostym kroku cała zawartość bufora (wszystkie dosłowne pliki HTML) są łączone w ciąg dynamicznych plików HTML.

(Mój przykład pokazuje, że dosłowny html jest wyprowadzany do bufora, który jest następnie dodawany do łańcucha html ... spójrz również na przykład JD Isaaks, aby zobaczyć zawijanie łańcucha html).

<?php // parent.php

//---------------------------------
$lvs_html  = "" ;

$lvs_html .= "<div>html</div>" ;
$lvs_html .= gf_component_assembler__without_ob( ) ;
$lvs_html .= "<div>more html</div>" ;

$lvs_html .= "----<br/>" ;

$lvs_html .= "<div>html</div>" ;
$lvs_html .= gf_component_assembler__with_ob( ) ;
$lvs_html .= "<div>more html</div>" ;

echo $lvs_html ;    
//    02 - component contents
//    html
//    01 - component header
//    03 - component footer
//    more html
//    ----
//    html
//    01 - component header
//    02 - component contents
//    03 - component footer
//    more html 

//---------------------------------
function gf_component_assembler__without_ob( ) 
  { 
    $lvs_html  = "<div>01 - component header</div>" ; // <table ><tr>" ;
    include( "component_contents.php" ) ;
    $lvs_html .= "<div>03 - component footer</div>" ; // </tr></table>" ;

    return $lvs_html ;
  } ;

//---------------------------------
function gf_component_assembler__with_ob( ) 
  { 
    $lvs_html  = "<div>01 - component header</div>" ; // <table ><tr>" ;

        ob_start();
        include( "component_contents.php" ) ;
    $lvs_html .= ob_get_clean();

    $lvs_html .= "<div>03 - component footer</div>" ; // </tr></table>" ;

    return $lvs_html ;
  } ;

//---------------------------------
?>

<!-- component_contents.php -->
  <div>
    02 - component contents
  </div>

4

Ta funkcja nie dotyczy tylko nagłówków. Dzięki temu możesz zrobić wiele interesujących rzeczy. Przykład: możesz podzielić swoją stronę na sekcje i użyć jej w następujący sposób:

$someTemplate->selectSection('header');
echo 'This is the header.';

$someTemplate->selectSection('content');
echo 'This is some content.';

Możesz przechwycić wygenerowany tutaj wynik i dodać go w dwóch całkowicie różnych miejscach w układzie.


Wygląda na to, czego szukam. Muszę renderować rzeczy do „sekcji” (pomyśl o plikach JS i CSS), ale muszę mieć możliwość wywoływania ich w szablonie (który ładuje się później niż nagłówek) ... Więc jeśli wywołam „$ this- > addcss ('specificCSStoThisView'); " Chcę, aby renderował się między tagami <head>. Wydaje mi się, że nie mogę google google. Czy możesz wskazać mi właściwy kierunek? Dziękuję Ci!
NoobishPro

2

W istniejących odpowiedziach nie wymieniono następujących elementów: Konfiguracja rozmiaru bufora Nagłówek HTTP i zagnieżdżanie.

Konfiguracja rozmiaru bufora dla ob_start:

ob_start(null, 4096); // Once the buffer size exceeds 4096 bytes, PHP automatically executes flush, ie. the buffer is emptied and sent out.

Powyższy kod poprawia wydajność serwera, ponieważ PHP wyśle ​​większe porcje danych, na przykład 4KB (bez wywołania ob_start, php wyśle ​​każde echo do przeglądarki).

Jeśli zaczniesz buforować bez wielkości porcji (np. Prosty ob_start ()), strona zostanie wysłana raz na końcu skryptu.

Buforowanie wyjściowe nie wpływa na nagłówki HTTP, są przetwarzane w inny sposób. Jednak ze względu na buforowanie możesz wysyłać nagłówki nawet po wysłaniu wyjścia, ponieważ nadal znajduje się ono w buforze.

ob_start();  // turns on output buffering
$foo->bar();  // all output goes only to buffer
ob_clean();  // delete the contents of the buffer, but remains buffering active
$foo->render(); // output goes to buffer
ob_flush(); // send buffer output
$none = ob_get_contents();  // buffer content is now an empty string
ob_end_clean();  // turn off output buffering

Ładnie wyjaśnione tutaj: https://phpfashion.com/everything-about-output-buffering-in-php


0

Nie, mylisz się, ale kierunek pasuje;)

Buforowanie wyników buforuje dane wyjściowe skryptu. To wszystko (krótko) wszystko po echolubprint . Nagłówki polegają na tym, że można je wysłać tylko wtedy, gdy jeszcze nie zostały wysłane. Ale HTTP mówi, że nagłówki są pierwszą transmisją. Więc jeśli wypisujesz coś po raz pierwszy (w żądaniu), nagłówki są wysyłane i nie możesz ustawić żadnych innych nagłówków.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.