Qual é o uso de ob_start () no php?

298

É ob_start()usado para output bufferingque os cabeçalhos sejam armazenados em buffer e não enviados para o navegador? Estou fazendo sentido aqui? Se não, então por que devemos usar ob_start()?

Aditya Shukla
fonte

Respostas:

481

Pense ob_start()no seguinte: "Comece a se lembrar de tudo o que normalmente seria produzido, mas ainda não faça nada com isso".

Por exemplo:

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

Em geral, existem duas outras funções com as quais você o emparelha ob_get_contents():, que basicamente fornece o que foi "salvo" no buffer desde que foi ligado ob_start()e, em seguida , ob_end_clean()ou ob_flush(), que pára de salvar as coisas e descarta o que foi salvo ou pára de salvar e produz tudo de uma vez, respectivamente.

Riley Dutton
fonte
55
Ótima explicação. Eu iria um passo além e substituir ob_get_contents()com ob_get_clean()e remover ob_end_clean()uma vez que ob_get_clean()executa essencialmente ambas as funções. Referência: php.net/manual/pt/function.ob-get-clean.php (PHP 4> = 4.3.0, PHP 5)
Con Antonakos
Presumo que o buffer de saída precise ser ativado no pedido de arquivo .ini para chamar ob_start();Isso está correto? O que acontece se não estiver ativado?
Kevin Wheeler
5
@Riley Dutton Você não está dizendo que por que o ob_start () é usado
Vishnu R Nair
Tive o mesmo problema, depois de corrigir meu código com ob_end_cleanele funciona como um encanto! Obrigado @Riley Dutton
Martins
160

Eu uso isso para que eu possa sair do PHP com muito HTML, mas não renderizá-lo. Isso me impede de armazená-lo como uma string que desativa o código de cores IDE.

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

Ao invés de:

<?php
$content = '<div>
    <span>text</span>
    <a href="#">link</a>
</div>';
?>
JD Isaacks
fonte
1
Isso pode ser usado como uma maneira de ter várias páginas html em um PHP e chamá-las via GET?
joshkrz
1
Suponho que sim, mas não parece uma boa ideia. Seria melhor carregá-los de modelos separados.
JD Isaacks
1
Note que esta técnica usa ob_get_clean(), não ob_end_clean()
Blazemonger
11
Nunca pensei nisso, é uma maneira incrivelmente amigável de se desenvolver! Além disso, ele remove a minha necessidade de ter o Javascript ou HTML como uma string no meu PHP, constantemente escapar \" etc, que é irritante
J-Dizzle
1
Seu visual fornece uma imagem clara dos benefícios do uso do ob_start.
klewis
86

A resposta aceita aqui descreve o que ob_start()faz - não o motivo pelo qual é usada (qual foi a pergunta).

Como declarado em outro lugar, ob_start()cria um buffer no qual a saída é gravada.

Mas ninguém mencionou que é possível empilhar vários buffers no PHP. Veja ob_get_level ().

Quanto ao porquê ....

  1. O envio de HTML para o navegador em partes maiores oferece um benefício de desempenho devido a uma sobrecarga de rede reduzida.

  2. A transmissão dos dados do PHP em partes maiores fornece um benefício de desempenho e capacidade, reduzindo o número de alternâncias de contexto necessárias

  3. A transmissão de grandes pedaços de dados para mod_gzip / mod_deflate oferece um benefício de desempenho, pois a compactação pode ser mais eficiente.

  4. armazenar em buffer a saída significa que você ainda pode manipular os cabeçalhos HTTP posteriormente no código

  5. A liberação explícita do buffer após a saída do [head] .... [/ head] pode permitir que o navegador comece a organizar outros recursos da página antes da conclusão do fluxo HTML.

  6. Capturar a saída em um buffer significa que ele pode ser redirecionado para outras funções, como email, ou copiado para um arquivo como uma representação em cache do conteúdo.

symcbean
fonte
29

Você tem isso ao contrário. ob_start não armazena em buffer os cabeçalhos, armazena em buffer o conteúdo. Usar ob_startpermite manter o conteúdo em um buffer do servidor até que você esteja pronto para exibi-lo.

Isso é comumente usado para que as páginas já possam enviar cabeçalhos 'depois que' eles 'enviaram' algum conteúdo (por exemplo, decidir redirecionar a meio da renderização de uma página).

Craige
fonte
3
+1 Eu também estava confuso quanto ao uso real da função. Sua resposta sobre seu uso durante o "redirecionamento" me lembrou todas as vezes que tive o erro "Cabeçalhos já enviados". Obrigado
pat
13

Eu prefiro:

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

isso é para esclarecer melhor a resposta de JD Isaaks ...

O problema com que você se depara com freqüência é que você está usando o php para gerar html de muitas fontes diferentes de php, e essas fontes são, por qualquer motivo, geradas de maneiras diferentes.

Às vezes, você possui conteúdo literal em html que deseja gerar diretamente no navegador; outras vezes, a saída está sendo criada dinamicamente (do lado do servidor).

O conteúdo dinâmico será sempre (?) Uma string. Agora você tem que combinar esse html dinâmico estrito com qualquer html literal, direto para exibição ... em uma estrutura de nó html significativa.

Isso geralmente força o desenvolvedor a agrupar todo o conteúdo direto para exibição em uma string (como JD Isaak estava discutindo) para que ele possa ser entregue / inserido corretamente em conjunto com o html dinâmico ... mesmo que você não realmente quero embrulhado.

Mas, usando os métodos ob _ ##, você pode evitar essa confusão de quebra de cadeia. Em vez disso, o conteúdo literal é enviado para o buffer. Em uma etapa fácil, todo o conteúdo do buffer (todo o seu html literal) é concatenado na sua seqüência de html dinâmico.

(Meu exemplo mostra a saída literal de html no buffer, que é adicionado a uma string html ... veja também o exemplo de JD Isaaks para ver a string-wrap-of-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>
dsdsdsdsd
fonte
4

Esta função não é apenas para cabeçalhos. Você pode fazer muitas coisas interessantes com isso. Exemplo: você pode dividir sua página em seções e usá-la assim:

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

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

Você pode capturar a saída gerada aqui e adicioná-la em dois lugares totalmente diferentes no seu layout.

jwueller
fonte
Esse tipo de parece com o que estou procurando. Preciso renderizar coisas para 'seções' (pense nos arquivos JS e CSS), mas preciso chamá-los no modelo (que é carregado depois do cabeçalho) ... Então, se eu chamar "$ this- > addcss ('specificCSStoThisView'); " Eu quero que ele seja renderizado entre as tags <head>. No entanto, não consigo pesquisar no Google. Você poderia me indicar a direção certa? Obrigado!
NoBishPro
2

O seguinte não é mencionado nas respostas existentes: Configuração do tamanho do buffer HTTP Header and Nesting.

Configuração do tamanho do buffer para 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.

O código acima melhora o desempenho do servidor, pois o PHP envia grandes quantidades de dados, por exemplo, 4KB (sem chamada ob_start, o php envia cada eco ao navegador).

Se você começar a armazenar em buffer sem o tamanho do pedaço (por exemplo, um simples ob_start ()), a página será enviada uma vez no final do script.

O buffer de saída não afeta os cabeçalhos HTTP, eles são processados ​​de maneira diferente. No entanto, devido ao buffer, você pode enviar os cabeçalhos mesmo após o envio, porque ele ainda está no buffer.

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

Bem explicado aqui: https://phpfashion.com/everything-about-output-buffering-in-php

sudip
fonte
0

Não, você está errado, mas a direção se encaixa;)

O buffer de saída armazena em buffer a saída de um script. Isso é (em suma) tudo depois echoou print. A coisa com os cabeçalhos é que eles só podem ser enviados, se ainda não tiverem sido enviados. Mas o HTTP diz que os cabeçalhos são os primeiros da transmissão. Portanto, se você produzir algo pela primeira vez (em uma solicitação), os cabeçalhos serão enviados e você não poderá definir outros cabeçalhos.

KingCrunch
fonte