2012-07-04 44 views
10

Nie wiem dlaczego, ale ten kod pracował dla mnie miesiąc temu ... może uaktualniłem php, ale nie pamiętam. Próbowaliśmy tego z PHP 5.2.17 i 5.3.6Obiekt klasy nie działa wewnątrz wywołania oddzwonienia

Dlaczego nie można użyć obiektu klasy wewnątrz wywołania zwrotnego funkcji 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### 

wyjściowa wynosi:

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

powinno być:

This is the awesome Title

Odpowiedz

10

To dlatego, że bufor wyjściowy jest niejawnie zaczerwieniona przez zakończenie skryptu.

W tym momencie PHP zniszczył już zmienne bez odniesienia, więc jeśli chodzi o wykonywanie funkcji zwrotnej, zmienna $f nie istnieje w zasięgu globalnym.

Możesz rozwiązać ten problem, przez jednoznaczne przepłukanie bufora, zanim zamknięcie rozpocznie niszczenie obiektów, umieszczając poniższy wiersz w skrypcie.

register_shutdown_function('ob_end_flush');

Edit:

Chciałbym dodać, że choć jest to obecnie akceptowane odpowiedź, która wyjaśnia „dlaczego”, rozwiązanie przedstawione tutaj nie odnosi się do korzeni przyczyna problemu; fakt, że jest używany global.

Wiele osób powie, że global jest złe, nie podając przyczyny. Oto jeden z powodów.

Odpowiedź udzielana przez Jack rozwiązanie daje więcej „najlepszych praktyk” (za pomocą zamknięć, aby utrzymać zmienną odniesienia) i powinny być traktowane jako właściwy sposób, aby unikać global w nowych codebases.

+2

Rzeczywiście, aby rozwinąć nieco: ważną częścią tego jest _ "niereferencyjne zmienne" _ są niszczone, a wspomniane nie są. Doskonały przykład, dlaczego 'global''s sprawia, że ​​kod jest trudniejszy, a właściwe przekazywanie referencji i argumentów jest preferowane. – Wrikken

2

Od strony podręcznika PHP ob_start i a bug report dowiedziałem się, że od 5,2, wszystkie obiekty są niszczone @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

ze stron podręcznika

+0

+1, dzięki za odniesienie do raportu o błędzie, nie wiedziałem, że to było faktycznie zmienione zachowanie (poza komentarzami autora pytania) – Leigh

+0

@Leigh: NP, miałem kłopot ze starym kawałkiem kodu, który napisałem chwilę plecy. Udało mi się ominąć to za pomocą zamknięcia, chociaż niektórzy ludzie radzą temu. Nawiasem mówiąc: czy wiesz, co jest lepsze, czy jest to tylko kwestia preferencji/nawyku? Nie mogę oprzeć się wrażeniu, że ma to coś wspólnego z ludźmi, którzy nie rozumieją, jak działają zamknięcia, niż z rzeczywistą jakością kodu. –

+1

Zgadzam się z tobą, to nie jest zły nawyk, aby ** zrozumieć **, dlaczego coś robisz. Używanie zamknięcia (IMHO) nie jest obejściem, jest to poprawny sposób na zachowanie referencji zmiennych i unikanie używania 'global'. Jak może być źle używać funkcji językowej w taki sposób, w jaki była przeznaczona. – Leigh

6

Powód tego został dobrze zarysowany przez Leigh. Korzystanie zamknięcie będzie działać lepiej w tym przypadku:

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

To dlatego, że zamknięcie będzie zachować odniesienie do $f żyjący pod koniec skryptu tak, że nie będzie się śmieci zebrane przed uruchomieniem funkcji zwrotnej.

Powiązane problemy