SO,
问题
它并不为人所知,但PHP允许比较对象——不仅在等式==
上,而且在<
和>
上。但是,它是如何工作的?那么,如果我想创建可比较的对象,它们应该遵循什么限制/规则?
最有用的情况是DateTime()
对象——它们持有特定的时间戳,并且可以进行比较(这具有逻辑意义(。在lxr上,对DateTime
有一些解释。但普通病例呢?
我有:
class C
{
protected $holder;
protected $mirror;
public function __construct($h = null)
{
$this->holder=$h;
$this->mirror=-1*$h;
}
}
$one = new C(1);
$two = new C(2);
//false, false, true: used $holder
var_dump($one>$two, $one==$two, $one<$two);
-如果我要更改属性声明顺序,它将使用$mirror
:
class C
{
//only order changed:
protected $mirror;
protected $holder;
public function __construct($h = null)
{
$this->holder=$h;
$this->mirror=-1*$h;
}
}
$one = new C(1);
$two = new C(2);
//true, false, false: used $mirror
var_dump($one>$two, $one==$two, $one<$two);
因此,"规则"之一似乎是它将使用第一个声明的属性。但我也不清楚它为什么使用protected
属性。
现在,更复杂的样本:
class Test
{
protected $a;
protected $b;
function __construct($a, $b)
{
$this->a = $a;
$this->b = $b;
}
}
$x = new Test(1, 2);
$y = new Test(1, 3);
// true, false, false
var_dump($x < $y, $x == $y, $x > $y);
$x = new Test(3, 1);
$y = new Test(2, 1);
// false, false, true
var_dump($x < $y, $x == $y, $x > $y);
-因此它将使用first not equal属性进行比较。但上面的代码片段只是一些情况。我想知道它到底是怎么发生的,为什么。因此,
问题
是:它是如何工作的?我的意思是,更详细的:
- 我可以相信PHP会使用第一个不相等的属性进行比较吗
- 如果属性数不相等,该怎么办?(即在代码执行期间,某些属性被动态添加到实例中(
- 我是否可以将
protected
/private
属性视为始终被计算用于此类比较
e.t.c.-所以如果有一些额外的条件/限制/规则会影响结果-请张贴。文档状态仅用于==
/===
比较。此外,比较不同类的实例是不可能的,因为它将返回false
(显然(。
PHP按顺序(按声明顺序(比较对象属性,并在找到的第一个不等属性处停止。这种行为没有被记录下来,所以除了查看PHP的来源之外,没有什么好说的。
未记录通常是"不要依赖它"的同义词。
struct _zend_object_handlers {
/* general object functions */
zend_object_add_ref_t add_ref;
zend_object_del_ref_t del_ref;
[...]
zend_object_compare_t compare_objects;
[...]
};
compare_objects
指向一个"接受两个对象"的函数,并根据该比较器定义的顺序返回-1.0,1(就像strcmp((对字符串所做的那样(
只有当两个操作数(对象(都指向同一个比较函数时,才使用此函数,但让我们继续使用这种情况
这就是DateTime
"添加"其功能以比较两个DateTime实例的地方,它只是定义了另一个特定于DateTime的compare_objects
函数,并将其放入描述其类的结构中。
static void date_register_classes(TSRMLS_D)
{
[...]
INIT_CLASS_ENTRY(ce_date, "DateTime", date_funcs_date);
ce_date.create_object = date_object_new_date;
[...]
date_object_handlers_date.compare_objects = date_object_compare_date;
因此,如果您想(确切地(了解两个DateTime实例是如何进行比较的,请查看date_object_compare_date
。
手册中描述的比较(至少在cmp(o1,o2(==0的情况下(似乎在zend_std_compare_objects
中实现。StdClass和一个简单的用户定义类(如(都使用它
<?php
class Foo { }
$a = new StdClass;
$b = new Foo;
$a > $b;
但是其他类(在php扩展中(确实设置了其他函数。DateTime、ArrayObject、PDOStatement,甚至闭包都使用不同的函数
但我还没有找到在脚本代码中定义比较函数/方法的方法(但看起来并不太难/太长(
PHP语言规范中定义了确切的行为,因此,您可以依赖它。
[…]如果对象的类型不同,则比较结果为FALSE。如果对象的类型相同,则使用上述数组比较来比较对象的属性。
阵列比较定义如下:
[…]对于元素数量相同的数组,将逐个考虑左侧操作数中的键,如果左侧操作数的下一个键存在于右侧操作数中,则比较相应的值。如果它们不相等,则包含较小值的数组被认为小于另一个,并且比较结束;否则,对下一个元素重复该过程。[…]如果所有值都相等,则认为数组相等。
只要将数组与对象和键的每一次提及与property交换,您就可以准确地描述这是如何工作的。我在上面的引用中省略了无用的数组细节。