2012-07-04 12 views
10

No sé por qué, pero este código funcionó para mí hace un mes ... tal vez actualicé el php pero no puedo recordarlo. Probé esto con PHP 5.2.17 y 5.3.6Objeto de clase que no funciona dentro de ob_start callback

¿Por qué no es posible usar un objeto de clase dentro de la devolución de llamada de una función ob_start?

<?php 
$f=new stdClass(); 
$f->title="awesome Title"; 

function callback($buffer) 
{ 
    global $f; 
    $buffer=str_replace("###TITLE###", $f->title, $buffer); 
    return $buffer; 
} 
ob_start("callback"); 
?> 

This is the ###TITLE### 

de salida es:

PHP Notice: Trying to get property of non-object in /Users/qxxx/Sites/test/test.php on line 8 
This is the 

debería ser:

This is the awesome Title

Respuesta

10

Esto es porque el búfer de salida se está implícitamente enrojecida por la terminación de la secuencia de comandos.

En este punto, PHP ya ha destruido variables sin referencia, por lo que cuando se trata de ejecutar su función de devolución de llamada, la variable $f no existe en el ámbito global.

Puede resolver esto al enjuagar explícitamente el búfer antes de que el apagado comience a destruir objetos, colocando la siguiente línea en algún lugar de su script.

register_shutdown_function('ob_end_flush');

Editar:

me gustaría añadir que a pesar de que esto es actualmente la respuesta aceptada que explica el "por qué", la solución proporcionada aquí no se refiere a la raíz causa del problema; el hecho de que se está usando global.

Mucha gente le dirá que global es malo, sin dar una razón por la cual. Aquí puedes ver una de las razones.

La respuesta proporcionada por Jack da una solución más "mejor práctica" (usando cierres para mantener la variable de referencia), y deben ser considerados como la forma correcta de evitar el uso de global en nuevas bases de código.

+2

De hecho, para elaborar un poco: una parte importante de esto es _ "variables sin referencia" _ se destruyen, las referencias no lo son. Un buen ejemplo de por qué 'global' tiende a hacer que el código sea más difícil, y se prefiere el paso apropiado de referencias y argumentos. – Wrikken

2

Desde la página del manual de php ob_start y a bug report he aprendido que, desde 5.2, todos los objetos se destruyen @ob_start

This function's behaviour has been changed in php 5.2.0:

<? 
    global $AP; 
    $AP = new ap; 
    ob_start("ob_end"); 
    function ob_end() 
    { 
     global $AP; 
     $r = $AP->test(); 
     return $r; 
    } 
    class ap 
    { 
     function test() 
     { 
      return "debug"; 
     } 
    } 
?> 

In older versions it shows: "debug". But latest php version causes error: PHP Fatal error: Call to a member function test() on > a non-object. And this is not a bug: http://bugs.php.net/bug.php?id=40104

de las páginas del manual

+0

+1, gracias por la referencia del informe de error, no sabía que en realidad había cambiado el comportamiento (aparte de los comentarios del autor de la pregunta) – Leigh

+0

@Leigh: NP, tuve algunos problemas con un código antiguo. Escribí un momento espalda. Logré sortearlo usando un cierre, aunque algunas personas aconsejan no hacerlo. Por cierto: ¿sabes cuál es mejor, o es solo una cuestión de preferencia/hábito? No puedo evitar pensar que tiene más que ver con personas que no entienden cómo funcionan los cierres que con una calidad de código real –

+1

Estoy de acuerdo con usted, no es una mala costumbre ** entender ** por qué está haciendo algo. Usar un cierre (en mi humilde opinión) no es una solución, es la forma correcta de preservar la referencia de la variable y evitar el uso de 'global'. ¿Cómo puede ser incorrecto utilizar una función de idioma de la manera en que fue diseñada? – Leigh

6

La razón de esto ha sido bien delineada por Leigh. El uso de un cierre funcionaría mejor en este caso:

ob_start(function($b) use ($f) { 
     return str_replace('###TITLE###', $f->title, $b); 
}); 

Esto es debido a que el cierre se mantendrá la referencia a $f vivos al final de la secuencia de comandos para que no quede basura recogida antes de ejecutar la función de devolución de llamada.

Cuestiones relacionadas