比较对象

当使用比较运算符 (==) 时,对象变量以简单的方式进行比较,即:如果两个对象实例具有相同的属性和值(值使用 == 比较),并且是同一个类的实例,则它们相等。

当使用同一性运算符 (===) 时,对象变量仅当它们引用同一个类的同一个实例时才相同。

示例将阐明这些规则。

示例 #1 对象比较示例

<?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
__construct($flag = true) {
$this->flag = $flag;
}
}

class
OtherFlag
{
public
$flag;

function
__construct($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);
?>

上面的示例将输出

Two instances of the same class
o1 == o2 : TRUE
o1 != o2 : FALSE
o1 === o2 : FALSE
o1 !== o2 : TRUE

Two references to the same instance
o1 == o2 : TRUE
o1 != o2 : FALSE
o1 === o2 : TRUE
o1 !== o2 : FALSE

Instances of two different classes
o1 == o2 : FALSE
o1 != o2 : TRUE
o1 === o2 : FALSE
o1 !== o2 : TRUE

注意:

扩展可以为它们的对象比较 (==) 定义自己的规则。

添加注释

用户贡献注释 12 则注释

jazfresh at hotmail.com
17 年前
请注意,在比较对象属性时,比较是递归的(至少在 PHP 5.2 中是如此)。也就是说,如果 $a->x 包含一个对象,那么它将以相同的方式与 $b->x 进行比较。请注意,这会导致递归错误
<?php
class Foo {
public
$x;
}
$a = new Foo();
$b = new Foo();
$a->x = $b;
$b->x = $a;

print_r($a == $b);
?>
结果为
PHP 致命错误:嵌套层级过深 - 递归依赖?在 test.php 的第 11 行
匿名
14 年前
应该记录使用 <> 运算符的比较。对于两个对象,至少在 PHP5.3 中,比较操作在找到第一个不相等的属性时停止并返回。

<?php

$o1
= new stdClass();
$o1->prop1 = 'c';
$o1->prop2 = 25;
$o1->prop3 = 201;
$o1->prop4 = 1000;

$o2 = new stdClass();
$o2->prop1 = 'c';
$o2->prop2 = 25;
$o2->prop3 = 200;
$o2->prop4 = 9999;

echo (int)(
$o1 < $o2); // 0
echo (int)($o1 > $o2); // 1

$o1->prop3 = 200;

echo (int)(
$o1 < $o2); // 1
echo (int)($o1 > $o2); // 0

?>
rnealxp at yahoo dot com
7 年前
这三个函数递归调用自身,并处理任何嵌套层级的数组/对象/值,并执行严格比较。此函数集的入口点将是 “valuesAreIdentical”。

<?php
function valuesAreIdentical($v1, $v2): bool {
$type1 = gettype($v1);
$type2 = gettype($v2);

if(
$type1 !== $type2){
return
false;
}

switch(
true){
case (
$type1==='boolean' || $type1==='integer' || $type1==='double' || $type1==='string'):
//Do strict comparison here.
if($v1 !== $v2){
return
false;
}
break;

case (
$type1==='array'):
$bool = arraysAreIdentical($v1, $v2);
if(
$bool===false){
return
false;
}
break;

case
'object':
$bool = objectsAreIdentical($v1,$v2);
if(
$bool===false){
return
false;
}
break;

case
'NULL':
//Since both types were of type NULL, consider their "values" equal.
break;

case
'resource':
//How to compare if at all?
break;

case
'unknown type':
//How to compare if at all?
break;
}
//end switch

//All tests passed.
return true;
}

function
objectsAreIdentical($o1, $o2): bool {
//See if loose comparison passes.
if($o1 != $o2){
return
false;
}

//Now do strict(er) comparison.
$objReflection1 = new ReflectionObject($o1);
$objReflection2 = new ReflectionObject($o2);

$arrProperties1 = $objReflection1->getProperties(ReflectionProperty::IS_PUBLIC);
$arrProperties2 = $objReflection2->getProperties(ReflectionProperty::IS_PUBLIC);

$bool = arraysAreIdentical($arrProperties1, $arrProperties2);
if(
$bool===false){
return
false;
}

foreach(
$arrProperties1 as $key=>$propName){
$bool = valuesAreIdentical($o1->$propName, $o2->$propName);
if(
$bool===false){
return
false;
}
}

//All tests passed.
return true;
}

function
arraysAreIdentical(array $arr1, array $arr2): bool {
$count = count($arr1);

//Require that they have the same size.
if(count($arr2) !== $count){
return
false;
}

//Require that they have the same keys.
$arrKeysInCommon = array_intersect_key($arr1, $arr2);
if(
count($arrKeysInCommon)!== $count){
return
false;
}

//Require that their keys be in the same order.
$arrKeys1 = array_keys($arr1);
$arrKeys2 = array_keys($arr2);
foreach(
$arrKeys1 as $key=>$val){
if(
$arrKeys1[$key] !== $arrKeys2[$key]){
return
false;
}
}

//They do have same keys and in same order.
foreach($arr1 as $key=>$val){
$bool = valuesAreIdentical($arr1[$key], $arr2[$key]);
if(
$bool===false){
return
false;
}
}

//All tests passed.
return true;
}
?>
rnealxp at yahoo dot com
4 年前
请使用此更正后的“valuesAreIdentical”函数版本,而不是我之前发布的版本(依赖项在之前的帖子中找到);如果管理员可以只替换函数代码段,太好了/谢谢,否则,抱歉。
<?php
public static function valuesAreIdentical($v1, $v2):bool{
$type1 = gettype($v1);
$type2 = gettype($v2);
switch(
true){
case (
$type1 !== $type2):
return
false;
case (
$type1==='boolean' || $type1==='integer' || $type1==='double' || $type1==='string'):
//Do strict comparison here.
return ($v1===$v2);
case (
$type1==='array'):
return
self::arraysAreIdentical($v1, $v2);
case (
$type1==='object'):
return
self::objectsAreIdentical($v1,$v2);
case (
$type1==='NULL'):
//Since both types were of type NULL, consider their "values" equal.
return true;
case (
$type1==='resource' || $type1==='unknown type'):
//How to compare if at all?
return true;
default:
return
true; //Code-flow not intended to arrive here.
} //end switch
}
?>
nhuhoai
10 年前
为了比较一个类中的两个对象,你可以使用这样的接口并为每个类自定义你的函数

<?php
interface EQU {
public static function
compare( EQU $me, EQU $you );
public function
equals( EQU $you );
}
?>

如果你有一个父类,你可以创建通用函数(不安全但适用于不太复杂的类)

<?php
abstract class SuperClass {
public function
__construct( ) {
// 做你需要做的
}
public static function
compare( $obj1, $obj2 ) {
return
serialize( $obj1 ) == serialize( $obj2 );
}
public function
equals( $obj ) {
return static::
compare( $this, $obj );
}
}
?>
rune at zedeler dot dk
17 年前
糟糕,看来我没有仔细检查下面的数组部分。
忘记测试数组是否长度相同,并且有一些括号不匹配。
这个应该会好些 :+)

<?
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;
}
?>
wbcarts at juno dot com
15 年前
使用 PHP 的 usort() 方法比较对象。

PHP 和 MySQL 都提供了对数据进行排序的方法,如果可能的话,最好使用它们。但是,由于本节介绍的是比较您自己的 PHP 对象(并且您可能需要更改 PHP 中的排序方法),因此以下是如何使用 PHP 的“用户定义”排序方法 usort() 和您自己的类 compare() 方法进行排序的示例。

<?php

/*
* Employee.php
*
* 此类定义了一个 compare() 方法,它告诉 PHP 此对象的排序规则
* 对于此对象 - 它是按 emp_id 排序。
*
*/
class Employee
{
public
$first;
public
$last;
public
$emp_id; // 我们感兴趣的属性...

public function __construct($emp_first, $emp_last, $emp_ID)
{
$this->first = $emp_first;
$this->last = $emp_last;
$this->emp_id = $emp_ID;
}

/*
* 定义此对象排序规则 - 使用 emp_id。
* 确保此函数返回 -1、0 或 1。
*/
public static function compare($a, $b)
{
if (
$a->emp_id < $b->emp_id) return -1;
else if(
$a->emp_id == $b->emp_id) return 0;
else return
1;
}

public function
__toString()
{
return
"Employee[first=$this->first, last=$this->last, emp_id=$this->emp_id]";
}
}

# 创建一个 PHP 数组并用 Employee 对象初始化它。
$employees = array(
new
Employee("John", "Smith", 345),
new
Employee("Jane", "Doe", 231),
new
Employee("Mike", "Barnes", 522),
new
Employee("Vicky", "Jones", 107),
new
Employee("John", "Doe", 2),
new
Employee("Kevin", "Patterson", 89)
);

# 使用 Employee compare() 方法对 $employees 数组进行排序。
usort($employees, array("Employee", "compare"));

# 打印结果
foreach($employees as $employee)
{
echo
$employee . '<br>';
}
?>

结果现在按 emp_id 排序

Employee[first=John, last=Doe, emp_id=2]
Employee[first=Kevin, last=Patterson, emp_id=89]
Employee[first=Vicky, last=Jones, emp_id=107]
Employee[first=Jane, last=Doe, emp_id=231]
Employee[first=John, last=Smith, emp_id=345]
Employee[first=Mike, last=Barnes, emp_id=522]

重要说明:您的 PHP 代码永远不会直接调用 Employee 的 compare() 方法,但 PHP 的 usort() 会多次调用它。另外,在定义排序规则时,请确保降至“基本类型”级别... 也就是说,降至数字或字符串,并且该函数返回 -1、0 或 1,以获得可靠且一致的结果。

另请参见:https://php.net/manual/en/function.usort.php 以获取更多有关 PHP 排序功能的示例。
cross+php at distal dot com
16 年前
为了回应“rune at zedeler dot dk”关于类内容相等的评论,我遇到了类似的问题。我想使用 sort() 对对象数组进行排序。

我知道我可以使用 usort() 来完成,但我习惯于 C++,您可以在其中定义允许比较的运算符。我在 zend 源代码中看到它调用了一个 compare_objects 函数,但我没有看到任何为对象实现该函数的方法。它必须是扩展才能提供该接口吗?

如果是这样,我想建议您允许在 PHP 的类定义中定义等效和/或比较运算。这样,rune 和我想做的事情就容易多了。
cpmjr1 at gmail dot com
1 年前
从文档中看不出来,但是相等比较运算符也会检查受保护和私有属性。

示例
<?php
class A { public $a = 0; private $b = 1; public function __construct($test) {$this->b = $test;}}
echo
"A(1) == A(2) " . var_export((new A(1)) == (new A(2)), true) . "\n";
echo
"A(1) == A(1) " . var_export((new A(1)) == (new A(1)), true) . "\n";
?>
输出
A(1) == A(2) false
A(1) == A(1) true
rune at zedeler dot dk
17 年前
我还没有找到内置函数来检查两个对象是否相同 - 也就是说,它们的所有字段是否都相同。
换句话说,

<?
class A {
var $x;
function __construct($x) { $this->x = $x; }

}
$identical1 = new A(42);
$identical2 = new A(42);
$different = new A('42');
?>

使用“==”比较对象将声称所有三个对象都相等。使用“===”比较将声称所有对象都不相等。
我没有找到内置函数来检查两个相同的对象是否
相同,但不与不同的对象相同。

以下函数可以做到这一点

<?
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;
}
?>
Hayley Watson
15 年前
这已经提到过(请参阅 jazfresh at hotmail.com 的说明),但这里更详细地说明一下,因为对于对象来说,== 和 === 之间的区别非常重要。

对象上的松散相等 (==) 是递归的:如果正在比较的两个对象的属性本身是对象,那么这些属性也将使用 == 进行比较。

<?php
class Link
{
public
$link; function __construct($link) { $this->link = $link; }
}
class
Leaf
{
public
$leaf; function __construct($leaf) { $this->leaf = $leaf; }
}

$leaf1 = new Leaf(42);
$leaf2 = new Leaf(42);

$link1 = new Link($leaf1);
$link2 = new Link($leaf2);

echo
"比较 Leaf 对象等效性:is \$leaf1==\$leaf2? ", ($leaf1 == $leaf2 ? "Yes" : "No"), "\n";
echo
"比较 Leaf 对象同一性:is \$leaf1===\$leaf2? ", ($leaf1 === $leaf2 ? "Yes" : "No"), "\n";
echo
"\n";
echo
"比较 Link 对象等效性:is \$link1==\$link2? ",($link1 == $link2 ? "Yes" : "No"), "\n";
echo
"比较 Link 对象同一性:is \$link1===\$link2? ", ($link1 === $link2 ? "Yes" : "No"), "\n";
?>

即使 $link1 和 $link2 包含不同的 Leaf 对象,它们仍然是等效的,因为 Leaf 对象本身是等效的。

实际上,在更适合使用 "===" 时使用 "==" 会导致严重的性能损失,特别是当对象很大或很复杂时。事实上,如果对象之间或其任何属性(递归地)存在循环关系,则由于隐含的无限循环,可能会导致致命错误。

<?php
class Foo { public $foo; }
$t = new Foo; $t->foo = $t;
$g = new Foo; $g->foo = $g;

echo
"严格身份: ", ($t===$g ? "True" : "False"),"\n";
echo
"松散等效: ", ($t==$g ? "True" : "False"), "\n";
?>

因此,应该优先使用 "===" 而不是 "==" 来比较对象;如果要比较两个不同的对象是否等效,请尝试通过检查合适的单个属性来进行比较。(也许 PHP 可以获得一个魔术方法 "__equals",用于评估 "=="?:) )
Oddant
11 年前
这个例子太让人困惑了,如果你不熟悉 PHP 的比较机制,在阅读完这个例子后,你可能会认为 "==" 实际上是在比较对象的类型。事实并非如此,它实际上是在比较对象的类型及其属性。

<?php

class A {
private
$value;
function
__construct ($value)
{
$this->value = $value;
}
}
class
B {
private
$value;
function
__construct ($value)
{
$this->value = $value;
}
}

$a1 = new A (1);
$a2 = new A (2);
$b1 = new B (1);

var_dump( $a1 == $a2 );
var_dump( $a1 == $b1 );
?>
To Top