2012-01-28 13 views
14

Właśnie przerobione mój algorytm detekcji rekurencji w moim zwierzakiem projektu dump_r()wykrywanie rekursji nieskończonej tablicy w PHP?

https://github.com/leeoniya/dump_r.php

wykrywania obiektów rekurencji nie jest zbyt trudne - użyć spl_object_hash(), aby uzyskać unikalny wewnętrzny identyfikator instancji obiektu , przechowuj go w dyktafonie i porównuj z nim podczas wysypywania innych węzłów.

do wykrywania rekursji tablic, jestem nieco zaintrygowany, nie znalazłem nic przydatnego. sam php jest w stanie zidentyfikować rekursję, choć wydaje się, że robi to o jeden cykl za późno. EDIT: NVM, występuje tam, gdzie trzeba :)

$arr = array(); 
$arr[] = array(&$arr); 
print_r($arr); 

nie musiał uciekać się do śledzenia wszystkiego w stosie rekurencji i zrobić płytkie porównań przed każdym innym elemencie tablicy?

każda pomoc będzie doceniona,
dzięki!

+0

lol - eeewwwww. – leeoniya

+1

Nie jestem odpowiedzią na twój quesiton, ale widziałem rozwiązania, które testują 'print_r ($ var, true)' dla łańcucha wskazującego rekursję. To jest tak nieprzyjemne, jak to tylko możliwe, ale działa ... Zobacz [tutaj] (http://noteslog.com/post/detecting-recursive-dependencies-in-php-composite-values/), aby uzyskać przyzwoity kompromis. – Basic

+0

Usunąłem/edytowałem mój komentarz, aby umieścić link do przykładu, ale zgadzam się, to śmierdzi – Basic

Odpowiedz

9

Ponieważ mechanizm PHP call-by-value, jedynym rozwiązaniem widzę tutaj jest iterację tablicy przez odniesienie i ustawić dowolną wartość w tym, co cię później sprawdzić, czy istnieje, aby dowiedzieć się, czy były tam wcześniej:

function iterate_array(&$arr){ 

    if(!is_array($arr)){ 
    print $arr; 
    return; 
    } 

    // if this key is present, it means you already walked this array 
    if(isset($arr['__been_here'])){ 
    print 'RECURSION'; 
    return; 
    } 

    $arr['__been_here'] = true; 

    foreach($arr as $key => &$value){ 

    // print your values here, or do your stuff 
    if($key !== '__been_here'){ 
     if(is_array($value)){ 
     iterate_array($value); 
     } 

     print $value; 
    } 
    } 

    // you need to unset it when done because you're working with a reference... 
    unset($arr['__been_here']); 

} 

można owinąć tę funkcję w innej funkcji, które przyjmuje wartości zamiast referencji, ale wtedy dostanie zawiadomienie rekursji z 2 poziom dalej. Myślę, że print_r też to robi.

+0

** to jest rozwiązanie, na które liczyłem - proste i niesamowite. – leeoniya

3

Ktoś mnie poprawi, jeśli się mylę, ale PHP faktycznie wykrywa rekursję w odpowiednim momencie. Twoje przypisanie tworzy po prostu dodatkowy cykl. Przykładem powinny być:

$arr = array(); 
$arr = array(&$arr); 

co spowoduje

array(1) { [0]=> &array(1) { [0]=> *RECURSION* } } 

jak oczekiwano.


Cóż, sam byłem trochę ciekaw, jak wykryć rekursję i zacząłem pracować w Google. Znalazłem ten artykuł http://noteslog.com/post/detecting-recursive-dependencies-in-php-composite-values/ i tego rozwiązania:

function hasRecursiveDependency($value) 
{ 
    //if PHP detects recursion in a $value, then a printed $value 
    //will contain at least one match for the pattern /\*RECURSION\*/ 
    $printed = print_r($value, true); 
    $recursionMetaUser = preg_match_all('@\*RECURSION\*@', $printed, $matches); 
    if ($recursionMetaUser == 0) 
    { 
     return false; 
    } 
    //if PHP detects recursion in a $value, then a serialized $value 
    //will contain matches for the pattern /\*RECURSION\*/ never because 
    //of metadata of the serialized $value, but only because of user data 
    $serialized = serialize($value); 
    $recursionUser = preg_match_all('@\*RECURSION\*@', $serialized, $matches); 
    //all the matches that are user data instead of metadata of the 
    //printed $value must be ignored 
    $result = $recursionMetaUser > $recursionUser; 
    return $result; 
} 
+0

masz rację. nie jest późno. ale nadal potrzebuję sposobu, aby zrobić to poza natywną funkcją. – leeoniya

+0

Cóż, to rozwiązanie nie jest dokładnie tym, na co miałem nadzieję, ponieważ bardzo obciąża duże struktury i polega na wewnętrznej niekontrolowanej głębokości print_r() lub serializacji, co jest jednym z powodów, dla których rozpocząłem projekt od początku, heh , ale http://www.phpsadness.com/ :( – leeoniya

Powiązane problemy