php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #34291 reference comparison: $a isIdenticalTo $b
Submitted: 2005-08-28 23:02 UTC Modified: 2016-03-27 08:44 UTC
Votes:1
Avg. Score:4.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:0 (0.0%)
Same OS:0 (0.0%)
From: csaba at alum dot mit dot edu Assigned: krakjoe (profile)
Status: Closed Package: *General Issues
PHP Version: 5.1.0RC1 OS:
Private report: No CVE-ID: None
 [2005-08-28 23:02 UTC] 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



Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2005-08-30 20:28 UTC] csaba at alum dot mit dot edu
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>";
?>
 [2016-03-27 08:44 UTC] krakjoe@php.net
-Status: Open +Status: Closed -Package: Feature/Change Request +Package: *General Issues -Assigned To: +Assigned To: krakjoe
 [2016-03-27 08:44 UTC] krakjoe@php.net
Sometime between version 5.3 and 5.4, the restriction that caused you to request this feature was lifted.

Sorry about the wait :)
 
PHP Copyright © 2001-2019 The PHP Group
All rights reserved.
Last updated: Fri Oct 18 16:01:28 2019 UTC