PHP中的对象比较

4

所以,

问题

很少有人知道,但是 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);

-因此,它将使用第一个不相等的属性进行比较。但是,上面的代码片段只是一些情况。我想确切地知道它是如何发生的以及为什么。

问题

问题是:它是如何工作的?我的意思是,更详细地说:

  • 我能依靠PHP使用第一个不相等的属性进行比较这个事实吗?
  • 如果属性的数量不相等会怎样?(即在代码执行期间动态添加了某些属性)
  • 我能将protected/private属性始终视为参与此类比较的属性吗?

等等 - 因此,如果有一些额外的条件/限制/规则会影响结果,请发布。 文档仅说明了 == / === 比较。另外,不同类的实例之间的比较是无关紧要的,因为它将返回false(显然)。

3个回答

3

PHP会按照声明顺序逐个比较对象属性,并在发现第一个不相等的属性时停止。这种行为没有文档记录,因此很遗憾除了查看PHP源代码之外,没有太多可以说的。

通常情况下,“没有文档记录”是“不要依赖它”的同义词。


不错。如果没有文档记录,那你怎么知道它会按照这种方式完成呢?我的当前想法也是一样的,但我想知道我是否可以依赖它。但是,例如通过lxr搜索并不有用。因此,我需要一些证明-这种行为是如预期的那样工作的。 - Alma Do
2
如果您真的想看看它是如何工作的,这是比较函数。虽然没有注释,但基本上:如果为对象定义了比较处理程序,它将调用它(例如对于DateTime)。 - user703016

2
PHP中的每个类都有一个关联的结构(在c代码中)处理程序函数,它看起来像:
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,甚至Closures都使用不同的函数。
但我还没有找到一种在脚本代码中定义比较函数/方法的方法(但也没有花太多时间去寻找)。

很好的解释,关于DateTime - 的确,我已经研究了内部实现(所以就像你发布的那样)。 - Alma Do

0
确切的行为在PHP语言规范中定义,因此您可以依赖它。
如果对象是不同类型的,则比较结果为FALSE。 如果对象是相同类型的,则使用上述数组比较比较对象的属性。
数组比较定义如下:
对于具有相同元素数量的数组,从左操作数开始考虑键,如果左操作数中的下一个键存在于右操作数中,则比较相应值。 如果它们不相等,则包含较小值的数组被视为小于另一个数组,并且比较结束;否则,重复该过程以处理下一个元素。 如果所有值都相等,则认为这些数组相等。
只需在脑海中将每个“array”提及替换为“object”,并将每个“key”替换为“property”,您就可以获得其确切描述。 我省略了上述引述中无用的数组细节。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接