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

Reply via email to