Archive for the ‘Module’ Kategorija

PHP Napaka Pri gnezdenju Ravni Pregloboko reurzivno odvisnost

12. marec, 2010

Sem namestil PHP 5.2 na enem od mojih testnih računalnikov danes in nekaj bitov kode, ki je prej delovala v redu v različici 5.1.6 vrgel usodne napake v novi različici. Sporočilo o napaki je bilo »Nivo gnezdanja pregloboko – reurzivna odvisnost?" in je trajalo nekaj časa

za sledenje korenu težave. To sem naredil narobe..

V PHP obstajata dva operaterja za primerjavo, == in ===. Na splošno je znano, da prvi ni strog glede tipa, drugi pa je. Tako, na primer

odmev ( false == 0 ); // Res

odmev ( false === 0 ); // napačno

– 0 je vse število in false je boolean

Moja težava je skotila z uporabo nestrožnega tipkanja z predmeti.

$a = nov MyObj();
$b = nov MyObj();
če( $a == $b )

Nisem preučiti, kaj počnem s to kodo.. Pri primerjanju dveh predmetov z uporabo nestrožnega operatorja za primerjavo (==) PHP primerja vse lastnosti predmetov in če se ujemajo s predmeti, se zdijo enaki. Če se ne ujemajo, niso enaki.. V veljavi, imamo reurzivno primerjavo vseh lastnosti vsakega predmeta, in vse njihove lastnosti, itd. dokler ne dosežemo osnovnih podatkovnih tipov, kot so nizi in splošna.

Če, Vendar pa, uporabljamo strogo primerjavo (===), PHP bo preveril, ali sta ti predmeti popolnoma isti predmet, ne le predmeti z enakimi lastnostmi.

razred MyObj
{
javni $p;
}

$a = nov MyObj();
$b = nov MyObj();
$c = nov MyObj();
$a->p = 1;
$b->p = 1;
$c->p = 2;
odmev ( $a == $c ); // napačno
odmev ( $a == $b ); // Res
odmev ( $a === $b ); // napačno

Težava se pojavi, če imate krožne sklice v lastnostih predmetov. Tako, na primer

razred MyObj
{
javni $p;
}
razred DrugoObj
{
javnih $q;
}

$a = nov MyObj();
$b = novo DrugoObj();
$a->p = $b;
$b->q = $a; // krožno sklicevanje: $a->p->q === $a

$c = nov MyObj();
$d = novo DrugoObj();
$c->p = $d;
$d->q = $c;// drugo krožno sklicevanje: $c->p->q === $c

odmev ( $a == $c ); // Usodna napaka:
Nivo gnezdanja pregloboko – reurzivna odvisnost?

Za primerjavo $a $c, PHP mora primerjati svoje lastnosti. Torej logika v PHP gre nekaj takega: $a == $c če $a->p == $c->p, če $a->p->q == $c->p->q če $a->p->q->p == $c->p->q->p itd.. Nedogled.

PHP 5.1 zdelo, da gladko čez problem nekako (verjetno po določeni stopnji ponovitve je preprosto vrnil napačno) – in ponavadi se je dobro izšlo. PHP 5.2 pravilno povzroči usodno napako zgoraj.

Ko enkrat zavleciš problem, rešitev je enostavna – uporaba stroge primerjave.

odmev ( $a === $c ); // napačno (in ni napake)

Stroga primerjava bo preprosto preverila, ali sta predmeti na istem mestu v pomnilniku in tako niti ne gleda vrednosti lastnosti.

N.B. Enak problem se lahko pojavijo pri uporabi negatenih operaterjev primerjave (uporabiti !== namesto !=) in pri uporabi in_array (tretji parameter in_array, da se navede stroga primerjava).