【问题标题】:Objects comparison in PHPPHP中的对象比较
【发布时间】:2018-11-03 22:31:13
【问题描述】:

所以,

问题

这不是众所周知的,但 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 属性进行比较。但上面的代码 sn-ps 只是一些情况。我想确切地知道它是如何发生的以及为什么。因此,

问题

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

  • 我可以相信 PHP 将使用第一个不相等属性进行比较的事实吗?
  • 如果属性数量不相等怎么办? (即在代码执行期间,一些属性被动态添加到实例中)
  • 我可以将protected/private 属性视为始终计入此类比较吗?

e.t.c. - 所以如果有一些额外的条件/限制/规则会影响结果 - 请张贴。 Documentation 仅用于 ==/=== 比较。此外,比较不同类的实例也不存在问题,因为它会返回false(很明显)。

【问题讨论】:

    标签: php object comparison


    【解决方案1】:

    PHP 按顺序(按声明顺序)比较对象属性并在找到的第一个不相等属性处停止。这种行为没有记录在案,所以遗憾的是,除了查看 PHP 的源代码之外,没有什么可说的。

    未记录通常是“不要依赖它”的同义词。

    【讨论】:

    • 好。如果没有记录,那么你怎么知道它会以这种方式完成?我目前的想法是一样的 - 但我想知道我是否可以依靠这一点。但是,例如,通过 lxr 搜索并没有帮助。因此,我想要一些证据来证明 - 这种行为是为了工作
    • 如果你真的想看看它是如何工作的,this is the comparison function。它没有注释,但基本上:如果为对象定义了比较处理程序,它将调用它(例如DateTime)。
    【解决方案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

    comparision described in the manual(至少对于 cmp(o1,o2)==0 的情况)似乎在 zend_std_compare_objects 中实现。 StdClass 和简单的用户定义类都使用它,例如

    <?php
    class Foo { }
    $a = new StdClass;
    $b = new Foo;
    
    $a > $b;
    

    但其他类(在 php 扩展中)确实设置了其他功能。 DateTime、ArrayObject、PDOStatement,甚至闭包都使用不同的函数。
    但是我还没有找到在脚本代码中定义比较函数/方法的方法(但看起来不太难/太长)

    【讨论】:

    • DateTime 的解释很好 - 事实上,我已经研究过内部实现(所以就像你发布的那样)
    【解决方案3】:

    PHP language specification 中定义了确切的行为,因此,您可以依赖它。

    […] 如果对象属于不同类型,则比较结果为 FALSE。如果对象属于同一类型,则使用上述数组比较比较对象的属性[sic]

    并且数组比较定义如下:

    […] 对于元素个数相同的数组,从左操作数开始的key一个一个地被考虑,如果左操作数中的下一个key存在于右手操作数中,则比较对应的值.如果它们不相等,则认为包含较小值的数组小于另一个,比较结束;否则,对下一个元素重复该过程。 […] 如果所有的值都相等,那么数组就被认为是相等的。

    只需在您的脑海中将每次提及的 arrayobjectkeyproperty 进行交换,您就拥有了这是如何工作的确切描述。我在上面的引用中省略了无用的数组细节。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多