COMPARISONS AND EQUALITY are NOT the same
I'm not sure that the PHP Example #1 above is clear enough. In my own experience, I have found there is a distinct difference between a "comparison" and a "test for equality". The difference is found in the possible return values of the function being used, for example.
/*
* Test two values for EQUALITY - returns (boolean) TRUE or FALSE.
*/
function equals($a, $b)
{
return ($a == $b);
}
/*
* COMPARE two values - returns (int) -1, 0, or 1.
*/
function compare($a, $b)
{
if($a < $b) return -1;
else if($a == $b) return 0;
else if($a > $b) return 1;
else return -1;
}
My examples clarify the difference between "making a comparison" and "testing for equality". You can substitute any of the "==" with "===" for example, but the point is on the possible return values of the function. All tests for EQUALITY will return TRUE or FALSE, and a COMPARISON will give a "<", "==", or ">" answers... which you can then use for sorting.
Сравняване на обекти
В PHP 5 сравняването на обекти е по-сложен процес, отколкото в PHP 4 и е в съответствие с това, което може да се очаква от един Обектно-ориентиран език (не че PHP 5 е такъв език).
При използването на оператора за сравнение (==), обектите се сравняват по прост начин, а именно: Две инстанции на обект са равни, ако имат едни и същи атрибути и стойности и са инстанции на един и същи клас.
От друга страна, при използването на оператора за идентичност (===), обектите са равни тогава, и само тогава, когато сочат към една и съща инстанция на един и същ клас.
Следващият пример ще изясни тези правила.
Example #1 Пример за сравняване на обекти в PHP 5
<?php
function bool2str($bool)
{
if ($bool === false) {
return 'FALSE';
} else {
return 'TRUE';
}
}
function compareObjects(&$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 Flag
{
public $flag;
function Flag($flag = true) {
$this->flag = $flag;
}
}
class OtherFlag
{
public $flag;
function OtherFlag($flag = true) {
$this->flag = $flag;
}
}
$o = new Flag();
$p = new Flag();
$q = $o;
$r = new OtherFlag();
echo "Две инстанции на един и същи клас\n";
compareObjects($o, $p);
echo "\nДве референции към една и съща инстанция\n";
compareObjects($o, $q);
echo "\nИнстанции на два отделни класа\n";
compareObjects($o, $r);
?>
Примерът по-горе ще изведе:
Две инстанции на един и същ клас o1 == o2 : TRUE o1 != o2 : FALSE o1 === o2 : FALSE o1 !== o2 : TRUE Две референции към една и съща инстанция o1 == o2 : TRUE o1 != o2 : FALSE o1 === o2 : TRUE o1 !== o2 : FALSE Инстанции на два отделни класа o1 == o2 : FALSE o1 != o2 : TRUE o1 === o2 : FALSE o1 !== o2 : TRUE
Забележка: Разширенията могат да дефинират свои собствени правила за сравняване на обекти.
Сравняване на обекти
06-Sep-2008 11:02
05-Mar-2008 05:50
In response to "rune at zedeler dot dk"s comment about class contents being equal, I have a similar issue. I want to sort an array of objects using sort().
I know I can do it with usort(), but I'm used to C++ where you can define operators that allow comparison. I see in the zend source code that it calls a compare_objects function, but I don't see any way to implement that function for an object. Would it have to be an extension to provide that interface?
If so, I'd like to suggest that you allow equivalence and/or comparison operations to be defined in a class definition in PHP. Then, the sorts of things rune and I want to do would be much easier.
11-Mar-2007 04:20
Note that classes deriving from the same parent aren't considered equal when comparing even using ==; they should also be objects of the same child class.
<?php
class Mom {
private $mAttribute;
public function Mom( $attribute ) {
$this->mAttribute = $attribute;
}
public function Attribute() {
return $this->mAttribute;
}
}
final class Sister extends Mom {
public function Sister( $attribute ) {
$this->Mom( $attribute );
}
}
final class Brother extends Mom {
public function Brother( $attribute ) {
$this->Mom( $attribute );
}
}
$sister = new Sister( 5 );
$brother = new Brother( 5 );
assert( $sister == $brother ); // will FAIL!
?>
This assertion will fail, because sister and brother are not of the same child class!
If you want to compare based on the parent class object type only, you might have to define a function for comparisons like these, and use it instead of the == operator:
<?php
function SiblingsEqual( $a, $b ) {
if ( !( $a instanceof Mom ) ) {
return false;
}
if ( !( $b instanceof Mom ) ) {
return false;
}
if ( $a->Attribute() != $b->Attribute() ) {
return false;
}
return true;
}
assert( SiblingsEqual( $sister, $brother ) ); // will succeed
?>
28-Feb-2007 05:34
Whoops, apparently I hadn't checked the array-part of the below very well.
Forgot to test if the arrays had same length, and had some misaligned parenthesis.
This one should work better :+)
<?
function deepCompare($a,$b) {
if(is_object($a) && is_object($b)) {
if(get_class($a)!=get_class($b))
return false;
foreach($a as $key => $val) {
if(!deepCompare($val,$b->$key))
return false;
}
return true;
}
else if(is_array($a) && is_array($b)) {
while(!is_null(key($a)) && !is_null(key($b))) {
if (key($a)!==key($b) || !deepCompare(current($a),current($b)))
return false;
next($a); next($b);
}
return is_null(key($a)) && is_null(key($b));
}
else
return $a===$b;
}
?>
28-Feb-2007 05:27
I haven't found a build-in function to check whether two obects are identical - that is, all their fields are identical.
In other words,
<?
class A {
var $x;
function __construct($x) { $this->x = $x; }
}
$identical1 = new A(42);
$identical2 = new A(42);
$different = new A('42');
?>
Comparing the objects with "==" will claim that all three of them are equal. Comparing with "===" will claim that all are un-equal.
I have found no build-in function to check that the two identicals are
identical, but not identical to the different.
The following function does that:
<?
function deepCompare($a,$b) {
if(is_object($a) && is_object($b)) {
if(get_class($a)!=get_class($b))
return false;
foreach($a as $key => $val) {
if(!deepCompare($val,$b->$key))
return false;
}
return true;
}
else if(is_array($a) && is_array($b)) {
while(!is_null(key($a) && !is_null(key($b)))) {
if (key($a)!==key($b) || !deepCompare(current($a),current($b)))
return false;
next($a); next($b);
}
return true;
}
else
return $a===$b;
}
?>
08-Dec-2006 11:36
Note that when comparing object attributes, the comparison is recursive (at least, it is with PHP 5.2). That is, if $a->x contains an object then that will be compared with $b->x in the same manner. Be aware that this can lead to recursion errors:
<?php
class Foo {
public $x;
}
$a = new Foo();
$b = new Foo();
$a->x = $b;
$b->x = $a;
print_r($a == $b);
?>
Results in:
PHP Fatal error: Nesting level too deep - recursive dependency? in test.php on line 11
