Я ўсталяваў PHP 5.2 на адным з маіх тэставых кампутараў сёння і некалькі біт кода, які раней працаваў нармальна ў версіі 5.1.6 выкінуў фатальныя памылкі ў новай версіі. Паведамленне пра памылку было «Занадта глыбокі ўзровень укладзенасці - рэкурсіўная залежнасць?», і гэта заняло крыху часу каб знайсці корань праблемы. Вось што я зрабіў не так.
У PHP ёсць два аператара параўнання, == і ===. Агульнавядома, што першая не мае строгіх патрабаванняў да тыпу, а вось другая. Такім чынам, напрыклад
рэха ( ілжыва == 0 ); // праўда
рэха ( хлусня === 0 ); // ілжывы
– 0 з'яўляецца цэлым лікам, а false - лагічным
Мая праблема ўзнікла з-за выкарыстання нестрогага ўводу з аб'ектамі.
$a = новы MyObj();
$b = новы MyObj();
калі( $a == $b )
…
Я не думаў, што я раблю з гэтым кодам. Пры параўнанні двух аб'ектаў з выкарыстаннем аператара нестрогага параўнання (==) PHP параўноўвае ўсе ўласцівасці аб'ектаў і, калі яны супадаюць, аб'екты лічацца роўнымі. Калі яны не супадаюць, яны не роўныя. Па сутнасці, мы маем рэкурсіўнае параўнанне ўсіх уласцівасцей кожнага аб'екта, і ўсе іх уласцівасці, і г.д.. пакуль мы не дасягнем асноўных тыпаў дадзеных, такіх як радкі і цэлыя лікі.
Калі, аднак, мы выкарыстоўваем строгае параўнанне (===), PHP праверыць, ці з'яўляюцца гэтыя два аб'екты аднолькавымі, не толькі аб'екты з аднолькавымі ўласцівасцямі.
клас MyObj
{
публічны $p;
}$a = новы MyObj();
$b = новы MyObj();
$c = новы MyObj();
$а->р = 1;
$б->р = 1;
$в->р = 2;
рэха ( $a == $c ); // ілжывы
рэха ( $a == $b ); // праўда
рэха ( $a === $b ); // ілжывы
Праблема ўзнікае, калі ва ўласцівасцях вашых аб'ектаў ёсць цыклічныя спасылкі. Такім чынам, напрыклад
клас MyObj
{
публічны $p;
}
клас OtherObj
{
публічны $q;
}$a = новы MyObj();
$b = новы OtherObj();
$а->p = $b;
$б->q = $a; // кругавая спасылка: $а->п->q === $a$c = новы MyObj();
$d = новы OtherObj();
$в->p = $d;
$д->q = $c;// іншая кругавая спасылка: $в->п->q === $cрэха ( $a == $c ); // Фатальная памылка:
Занадта глыбокі ўзровень укладзенасці – рэкурсіўная залежнасць?
Каб параўнаць $a з $c, PHP павінен параўнаць іх уласцівасці. Такім чынам, логіка ў PHP выглядае прыкладна так: $a == $c, калі $a->p == $c->p, калі $a->п->q == $c->п->q, калі $a->п->д->p == $c->п->д->р і г.д. бясконца.
PHP 5.1 здавалася, неяк згладзіць праблему (верагодна, пасля пэўнага ўзроўню рэкурсіі ён проста вярнуўся ілжывым) – і звычайна гэта атрымлівалася добра. PHP 5.2 правільна стварае фатальную памылку вышэй.
Як толькі вы ведаеце праблему, рашэнне лёгкае – выкарыстоўваць строгае параўнанне.
рэха ( $a === $c ); // ілжывы (і ніякай памылкі)
Строгае параўнанне проста правярае, ці знаходзяцца два аб'екты ў адным і тым жа месцы ў памяці, і таму нават не разглядае значэнні ўласцівасцей.
N.B. Такая ж праблема можа ўзнікнуць пры выкарыстанні адмоўленых аператараў параўнання (выкарыстоўваць !== замест !=) і пры выкарыстанні in_array (выкарыстоўвайце трэці параметр in_array, каб паказаць строгае параўнанне).