If you want to test the existance of objects in arrays like in_array but with very strict checking in PHP4 (in order to avoid the "Nesting level too deep - recursive dependency?" error). i wrote the following function.
All objects that can be compared must extends comparable and call the comparable constructor. It will then create a serial number different on each objects.
I don't think it is the ultimate solution because arrays can contains loops and this won't be checked here. And if there is a recursive dependency between objects that do not extends comparable, you will still have the error.
Sometimes I think I don't like PHP very much ...
<?php
class comparable {
// Don't forget to call this constructor in sub-classes
function comparable(){
if(!isset($GLOBALS[__FILE__.'/class:comparable']))
$GLOBALS[__FILE__.'/class:comparable'] = 1;
$this->comparableSerial = $GLOBALS[__FILE__.'/class:comparable']++;
}
}
function exact_in_array(&$needle, &$haystack){
foreach($haystack as $k=>$v){
$elem = &$haystack[$k];
if(
is_object($needle) and is_object($elem) and
is_a($needle, 'comparable') and is_a($elem, 'comparable'))
{
if( get_class($needle) === get_class($elem) and
$needle->comparableSerial == $elem->comparableSerial)
return true;
}else{
// Uncomment this line to know which classes do not extends
// comparable and fail the test with Nesting level too deep error
//printf(
// "%s(%s) === %s(%s)",
// $needle, get_class($needle), $elem, get_class($elem));
if($needle === $elem) return true;
}
unset($elem);
}
return false;
}
?>
Porównywanie obiektów
W PHP 4 obiekty są porównywane w bardzo prosty sposób, to znaczy dwie instancje obiektów są uważane za równe, jeśli posiadają te same atrybuty i ich wartości, a także są instancjami tej samej klasy. Podobne reguły są stosowane, jeśli dwa obiekty są porównywane za pomocą operatora identyczności (===).
Example #1 Przykład porównania obiektów w PHP 4
<?php
function bool2str($bool) {
if ($bool === false) {
return 'FALSE';
} else {
return 'TRUE';
}
}
function porownajObiekty(&$o1, &$o2) {
echo 'o1 == o2 : '.bool2str($o1 == $o2)."\n";
echo 'o1 != o2 : '.bool2str($o1 != $o2)."\n";
echo 'o1 === o2 : '.bool2str($o1 === $o2)."\n";
echo 'o1 !== o2 : '.bool2str($o1 !== $o2)."\n";
}
class Flaga {
var $flag;
function Flaga($flag=true) {
$this->flag = $flag;
}
}
class przelaczalanaFlaga extends Flaga {
function turnOn() {
$this->flag = true;
}
function turnOff() {
$this->flag = false;
}
}
$o = new Flaga();
$p = new Flaga(false);
$q = new Flaga();
$r = new przelaczalnaFlaga();
echo "Porównaj instancje stworzone z tymi samymi argumentami\n";
porownajObiekty($o, $q);
echo "\nPorównaj instancje stworzone z różnymi argumentami\n";
porownajObiekty($o, $p);
echo "\nPorównaj instancję klasy nadrzędnej z instancją klasy podrzędnej\n";
porownajObiekty($o, $r);
?>
Powyższy przykład wyświetli:
Porównaj instancje stworzone z tymi samymi argumentami o1 == o2 : TRUE o1 != o2 : FALSE o1 === o2 : TRUE o1 !== o2 : FALSE Porównaj instancje stworzone z różnymi argumentami o1 == o2 : FALSE o1 != o2 : TRUE o1 === o2 : FALSE o1 !== o2 : TRUE Porównaj instancję klasy nadrzędnej z instancją klasy podrzędnej o1 == o2 : FALSE o1 != o2 : TRUE o1 === o2 : FALSE o1 !== o2 : TRUE
Wynik działania powyższego skryptu jest całkowicie przewidywalny na podstawie przedstawionych wyżej reguł. Tylko instancje o tych samych wartościach tych samych atrybutów, pochodzące z tej samej klasy, są uznawane za równe i identyczne.
Nawet w przypadku kompozycji obiektów stosowane są te same reguły porównywania. W poniższym przykładzie stworzona została klasa-pojemnik, która zawiera tablicę asocjacyjną obiektów klasy Flaga.
Example #2 Porównywanie obiektów złożonych w PHP 4
<?php
class ZbiorFlag {
var $set;
function ZbiorFlag($flagArr = array()) {
$this->set = $flagArr;
}
function addFlag($name, $flag) {
$this->set[$name] = $flag;
}
function removeFlag($name) {
if (array_key_exists($name, $this->set)) {
unset($this->set[$name]);
}
}
}
$u = new ZbiorFlag();
$u->addFlag('flag1', $o);
$u->addFlag('flag2', $p);
$v = new ZbiorFlag(array('flag1'=>$q, 'flag2'=>$p));
$w = new ZbiorFlag(array('flag1'=>$q));
echo "\nObiekty złożone u(o,p) i v(q,p)\n";
porownajObiekty($u, $v);
echo "\nu(o,p) i w(q)\n";
porownajObiekty($u, $w);
?>
Powyższy przykład wyświetli:
Obiekty złożone u(o,p) i v(q,p) o1 == o2 : TRUE o1 != o2 : FALSE o1 === o2 : TRUE o1 !== o2 : FALSE u(o,p) i w(q) o1 == o2 : FALSE o1 != o2 : TRUE o1 === o2 : FALSE o1 !== o2 : TRUE
Porównywanie obiektów
16-May-2007 04:17
29-Mar-2006 05:15
If youre just checking to see if the variables both reference the same object, instead of having a variable set up beforehand you could do away with the GLOBALS and have something like..
e.g.
<?php
class Foo {
var $serial;
function Foo() {
// Rest of constructor...
}
// Rest of class definition...
}
$baz->serial = -1;
$bar->serial = time();
if($bar->serial == $baz->serial) {
echo "Same";
}
?>
29-Apr-2005 02:24
Using globals isn't really well... you can use pattern singleton to verify this.
09-Apr-2004 06:44
An addendum to the post below:
If you are comparing two objects and you know that they will be of the same type (you're just not sure if they refer to the same object or not), then there is an easier and faster way to do the comparison, and this also avoids the infinite recursion problem with circular references described in the post below.
In the constructor of your object, set a "serial" attribute from a global variable that is incremented whenever a new object is created. Then you just have to compare serial numbers to see if the objects are the same.
e.g.
<?php
$FooSerial = 0;
class Foo {
var $serial;
function Foo() {
$this->serial = $GLOBALS['FooSerial']++;
// Rest of constructor...
}
// Rest of class definition...
}
if($bar->serial == $baz->serial) {
echo "Same";
}
?>
08-Apr-2004 06:18
PHP4 compares two objects (say, $a and $b) by comparing the type and all the attributes. If an attribute is an object, PHP4 will recursively call "if($a.attribute === $b.attribute)" to determine equality. However, this is a problem if a circular reference has been formed. The recursion will go on forever, and you will get the error message:
"Fatal error: Nesting level too deep - recursive dependency?"
Example, where the comparison will never terminate because PHP4 will forever recurse with comparisons of the attribute.
<?php
class Test {
var $obj;
}
$foo =& new Test;
$bar =& new Test;
$foo->obj =& $bar; // Make circular reference
$bar->obj =& $foo;
if($foo === $bar) {
baz();
}
?>
First PHP4 does ($foo === $bar), which expands into ($foo.obj === $bar.obj), which expands into ($bar.obj === $foo.obj), and so on and so on.
To avoid this situation, you must compare objects manually by comparing the two object's attributes and avoiding comparisons on attributes where a circular reference could arise.
This issue is easily avoided in PHP5, where objects can be compared via references rather than the object contents.
