2011-01-03 24 views
12

Zauważyłem, że czasami debug_backtrace() nie zawiera numeru linii dla połączenia. Czy jest jakiś powód, dlaczego tak się dzieje i jakikolwiek sposób to poprawić?Dlaczego funkcja debug_backtrace() czasami nie zawiera numeru wiersza?

Z góry dziękuję.

P.S. I tak, wywołania, w których pominięto numery linii, to mój własny kod, a nie wewnętrzny kod PHP.

+4

Interesujące. Czy możesz wysłać przykład? – deceze

+1

Czy jest to być może wewnątrz wyjątku, zamknięcia, kodu evaled, funkcji tick, obsługi błędów (w zasadzie dowolny kod, który działa poza zwykłym stosem wykonania)? Poza tym, nie rozumiem, dlaczego nie otrzymasz numerów linii (przynajmniej bez przykładu) ... – ircmaxell

+0

@deceze - Kod jest zbyt skomplikowany, by opublikować przykład. Chciałbym móc, ale najprawdopodobniej potrwałoby to kilka godzin lub dłużej, aby zidentyfikować coś na tyle prostego, by móc pisać i nie jest to dla mnie zbyt dużym problemem, aby spędzić cały ten czas. – MikeSchinkel

Odpowiedz

4

myślę, że to jest wymieniony jako backtrace PHP Bug

debugowania pokazuje nazwę pliku i lineno wywołania skryptu. W przypadku, gdy funkcja jest wywoływana z wnętrza funkcji wewnętrznej (może być jako oddzwonienie) nie można ustawić nazwy pliku ani bielizny pościelowej.

+0

Dzięki za zbadanie tego linku. Nie sądzę, że kod jest wywoływany przez funkcję wewnętrzną, ale sprawdzę. – MikeSchinkel

9

Rozważmy następujący kod:

<? 
class BtTest 
{ 
    public function getTheItem() 
    { 
    var_dump(debug_backtrace(false)); 
    $bt = debug_backtrace(false); 
    return $bt[1]; 
    } 

    public function __call($methodName, $methodArgs) 
    { 
    return $this->getTheItem(); 
    } 
} 

$o = new BtTest(); 
$bti = $o->test(); 

assert('array_key_exists("function", $bti)'); 
assert('array_key_exists("line", $bti)'); 
assert('array_key_exists("file", $bti)'); 

Realizacja powyższego przykładu generuje następujące dane wyjściowe:

array(3) { 
    [0]=> 
    array(6) { 
    ["file"]=> 
    string(53) "/somewhere/in/the/filesystem/tests/bt-test-so.php" 
    ["line"]=> 
    int(13) 
    ["function"]=> 
    string(10) "getTheItem" 
    ["class"]=> 
    string(6) "BtTest" 
    ["type"]=> 
    string(2) "->" 
    ["args"]=> 
    array(0) { 
    } 
    } 
    [1]=> 
    array(4) { 
    ["function"]=> 
    string(6) "__call" 
    ["class"]=> 
    string(6) "BtTest" 
    ["type"]=> 
    string(2) "->" 
    ["args"]=> 
    array(2) { 
     [0]=> 
     &string(4) "test" 
     [1]=> 
     &array(0) { 
     } 
    } 
    } 
    [2]=> 
    array(6) { 
    ["file"]=> 
    string(53) "/somewhere/in/the/filesystem/tests/bt-test-so.php" 
    ["line"]=> 
    int(18) 
    ["function"]=> 
    string(4) "test" 
    ["class"]=> 
    string(6) "BtTest" 
    ["type"]=> 
    string(2) "->" 
    ["args"]=> 
    array(0) { 
    } 
    } 
} 
PHP Warning: assert(): Assertion "array_key_exists("line", $bti)" failed in /somewhere/in/the/filesystem/tests/bt-test-so.php on line 21 
PHP Warning: assert(): Assertion "array_key_exists("file", $bti)" failed in /somewhere/in/the/filesystem/tests/bt-test-so.php on line 22 

pierwszej pozycji ślad (indeks 0) mówi pośrednio (poprzez line i file przedmiotów), że metoda getTheItem została wywołana z metody __call.

Drugi element backtrace (indeks 1) mówi, że metoda __call nazwano od gdzieś (brak line i file pozycji).

Trzeci ślad śledzenia (indeks 2) mówi, że metoda test została wywołana z globalnego zakresu skryptu.

Miejsce wywołania metody __call jest prawdopodobnie w pewnym kodzie rozpoznawania metody gdzieś w kodzie interpretatora php. Istnieją dwie możliwości jego naprawy. Druga pozycja powinna odnosić się do pliku kodu źródłowego tłumacza, a druga lub trzecia pozycja śledzenia wstecznego powinny zostać scalone w jeden. Osobiście wolałbym drugie rozwiązanie, ponieważ wewnętrzne ustawienia interpretera nie są dla mnie interesujące (tak wyglądają w śledzeniu Pythona), ale rozumiem, że czasami pierwsze rozwiązanie zapewnia bardziej wyraźny ślad (zwłaszcza gdy jest to wywołanie zwrotne, które jest wywołany z wewnętrznych elementów).

Wygląda na to, że programista (y) odpowiedzialny za (lub przynajmniej utrzymanie) kod funkcji debug_backtrace nie postrzega go jako błąd lub może nie ma łatwego sposobu na jego naprawienie. Byłoby dobrze wypełnić elementy line i file z niektórymi wartościami uchwytów (np. <unknown-file> i 0 lub nawet nulls) i podkreślić je w dokumentacji. Jeśli ktoś nie przekonuje ich, aby to zrobić, wystarczy zająć się specjalnym przypadkiem w swoim kodzie.

Napisałem powyżej, aby podzielić się moim zrozumieniem dziwnego zachowania funkcji.Jeśli ktoś ma chęć do walki o nieco lepszego świata, oto linki do niektórych powiązanych raportów o błędach:

Najstarszy raport pochodzi z 2003 roku, więc nie powinieneś liczyć na szybką naprawę :)

+0

Dziękuję bardzo za szczegółową odpowiedź. Wspaniała robota! – MikeSchinkel

1

Bez względu na "błąd", "cechę", cokolwiek ludzie, którzy utrzymują PHP chcieliby powiedzieć, debug_backtrace() nie działa tak, jak bym się spodziewał.

Oto moje rozwiązanie (że jest brzydki, ale działa dla mnie):

function dbg($msg="") 
{ 
    ob_start(); 
    debug_print_backtrace(0,1); 
    $_ = ob_get_clean(); 
    list($ignore,$line_number) = explode(':', $_); 
    $line_number += 0; 

    $backtrace = debug_backtrace(0); 
    extract($backtrace[1]); 
    echo "<pre>$class::$function($msg) : $line_number</pre>"; 
} 

debug_print_backtrace funkcja PHP (0,1); będzie produkować coś takiego:

# 0 dbg-> ping (290), zwanego w [/path/to/filename.php:290]

ponieważ tylko echo śladu, muszę ob_get_clean() to jako ciąg. Potem analizuję to.

W mojej realizacji, chcę tylko wiedzieć, klasę, funkcja, numer linii, oraz opcjonalnie wiadomość ciąg z funkcji wywołującej. debug_backtrace() zapewnia prawidłową klasę i funkcję, ale nie numer linii. Właśnie dlatego muszę pobrać numer linii z funkcji debug_print_backtrace().

Za punkty bonusowe ... jak to jest, że funkcja debug_print_backtrace() "zna" numer wiersza, ale debug_backtrace() [sporadycznie] nie, eh ??? ... to tajemnica ...

Powiązane problemy