ID: 34291 User updated by: csaba at alum dot mit dot edu Reported By: csaba at alum dot mit dot edu Status: Open Bug Type: Feature/Change Request PHP Version: 5.1.0RC1 New Comment:
OK, I was a bit hasty in what I recommended. In particular, there are two distinct cases: In one case, we want to know whether two references are the same. In the second, we'd like to know whether the values of two references are the same. The latter is the same as === except for arrays. So, I have written a function, isIdentical to do both of these. For the case of arrays and ===, I poke a new element onto one array and see if it shows up on the other. For the reference checking, I take a similar approach, except that one has to be careful with arrays, because any reference pointing to the original array that is poked is destroyed so this has to be fixed up. That is the reason for the two foreach loops - it detects self references that were destroyed and fixes them. The whole methodology employed in the example below - see what happens if you poke at it - does not give one the warm fuzzies. I'd still prefer to see isIdentical implemented as a native PHP function. function isIdentical(&$ref1, &$ref2, $referencesP=false) { // if $referencesP is true, isIdentical returns true // iff $ref1====$ref2. That is, if // $ref2=somethingElse changes $ref1, to // somethingElse, too (Ie. the same reference) // if $referencesP is false, isIdentical is the same // as $ref1===$ref2 for non objects/arrays. // For objects/arrays $ref1===$ref2 iff a change // in (a property of) $ref2 is reflected in $ref1 // (ie. the same object/array) if (gettype($ref1)!=($type=gettype($ref2))) return false; if ($arrayP=($type=="array")) { if (count($ref1)!=count($ref2)) return false; if (!$referencesP) {// are $ref1,$ref2 the same object $test = "isSameObjectTest"; while (array_key_exists($test, $ref2)) $test .= rand(); if (array_key_exists($test, $ref1)) return false; $ref2[$test] = 13; $result = array_key_exists($test,$ref1); unset ($ref2[$test]); return $result; } $aType = array(); foreach ($ref2 as $key=>$val) $aType[$key] = gettype($val); } // accounts for objects, too. elseif (!$referencesP) return $ref1===$ref2; $tmp = $ref2; $ref2 = ($type=="string") ? 13 : "fred"; $result = gettype($ref1)!=$type; // now we must repair the damage $ref2 = $tmp; if ($arrayP) foreach ($ref2 as $key=>&$ref) if ($aType[$key]!=gettype($ref)) $ref=&$ref2; return $result; } Csaba Gabor from Vienna references: //for comparison, see http://php.net/operators.comparison //http://at2.php.net/manual/en/language.operators.array.php //http://at2.php.net/manual/en/language.oop5.object-comparison.php Tested with: <?php $a = array(7); $a[] = &$b; $b = array(8); $b[] = &$a; $c = array(9); $c[] = &$a; print "<pre>"; print "GLOBALS test " . (isIdentical($GLOBALS, $GLOBALS["GLOBALS"], true) ? "passed" : "failed"); print "\nDouble test " . (isIdentical($b[1], $c[1], true) ? "passed\n" : "failed\n"); $c[2] = "test from c"; $b[3] = "test from b"; $a[4] = "test from a"; var_dump($a); print "\n"; var_dump($b); print "\n"; var_dump($c); print "</pre>"; ?> Previous Comments: ------------------------------------------------------------------------ [2005-08-28 23:02:51] csaba at alum dot mit dot edu Description: ------------ I would like to recommend a (boolean) operator: $ref1 isIdenticalTo $ref2 to compare whether two references are identical. A main use of this is in tree traversal. For example: $a = array(7); $a[] = &$a; // we now have a self reference print $a[1][1][1][0]; // => 7. All is OK if ($a==$a[1]) print "same"; // Fails Both $a==$a[1] and $a===$a[1] will fail because the nesting level is too deep. This is in agreement with the documentation, which says that values are tested. If I could do isIdenticalTo however (one could not use ==== with a straight face), then by placing the references of subarrays encountered onto an $aVisited array, I could run through them myself and check with isIdenticalTo and thus avoid exceeding a nesting level. An example where this (appropriately) happens is with $GLOBALS, since $GLOBALS["GLOBALS"] isIdenticalTo $GLOBALS. Thanks for considering this, Csaba Gabor from Vienna ------------------------------------------------------------------------ -- Edit this bug report at http://bugs.php.net/?id=34291&edit=1