PHP中有__equals方法,就像在Java中一样吗?

时间:2013-06-09 10:21:09

标签: php oop equals

您是否可以在PHP中使用模式或魔术方法来定义何时比较类的两个实例?

例如,在Java中,我可以轻松覆盖equals方法,并创建一种自定义方式来检查和比较两个实例。

5 个答案:

答案 0 :(得分:28)

总之一句话?没有。没有__equals魔法。有一个完整的魔术方法列表in the manual

你可以做到

$myObject1 == $myObject2

如果它们具有相同的属性和值,则认为它们相等,并且是同一类的实例。

我自己经常希望这种类型的方法,但我认为更有用的方法是__compare()方法,可以为任何比较运算符调用<,>,==,== =,等已经存在PHP的内置类,如PHP internals wiki中所示,并且有一个例子说明它如何在PHPInternals book中实现: -

  

compare_objects

int (*compare)(zval *object1, zval *object2 TSRMLS_DC)
     

比较两个对象。用于运算符==,!=,<,>,⇐和> =。   实现应该遵循这些规则 - 对于共享相同比较处理程序的任何对象a,b和c:

我用来实现这一目标的一种方法是实现Comparable接口,例如: -

interface Comparable
{
    /**
     * @param Comparable $other
     * 
     * @return Int -1, 0 or 1 Depending on result of comparison
     */
    public function compareTo(Comparable $other);
}

可以在http://www.php.net/manual/en/language.oop5.php找到对象比较的详细信息以及其他与OOP相关的内容。

<击> This may be implemented in PHP 7

现在有一个可以使用composer安装的实现。 https://github.com/Fleshgrinder/php-comparable

答案 1 :(得分:7)

可悲的是,但你可以很容易地复制一些东西。例如: -

<?php
interface IComparable {
    public function compare(self $subject);
}

class Foo implements IComparable {
    public function compare(self $subject) {
        return $this->__toString() === $subject->__toString();
    }
    public function __toString() {
        return serialize($this);
    }
}

function compare(IComparable $a, IComparable $b) {
    return $a->compare($b);
}

$a = new Foo;
$b = new Foo;

var_dump(compare($a, $b)); //true

$a->name = 'A';
$b->name = 'B';

var_dump(compare($a, $b)); //false

它并不是特别优雅,但应该让你上路。

安东尼。

答案 2 :(得分:4)

在大多数情况下,首先关闭==运算符就足够了,尤其是在我们讨论值对象时。如果您希望能够将实例与标量值进行比较,请务必提供__toString方法。

<?php

final class ValueObject {

    private $value;

    public function __construct($value) {
        $this->value = $value;
    }

    public function __toString() {
        return (string) $this->value;
    }

}

$a = new ValueObject(0);
$b = new ValueObject(1);

var_dump(
    $a == $b,  // bool(false)
    $a == $a,  // bool(true)
    $b == $b,  // bool(true)
    $a == '0', // bool(true)
    $b == '1'  // bool(true)
);

有一个问题,你无法比较字符串以外的标量类型(至少在PHP 5和7中没有),因为它会抱怨实例无法转换为所需的值。因此,您始终需要确保与之比较的值类型是字符串。

如果您想要更多,例如你想要将输入小写或处理浮点值直到达到一定的精度,你需要一个不同的方法。处理此问题的一种方法如下。

<?php

interface Comparable {

    function compareTo(Comparable $other): int;

}

function class_compare(Comparable $a, Comparable $b): int {
    return $a->compareTo($b);
}

final class C implements Comparable {

    private $value;

    public function __construct(int $value) {
        $this->value = $value;
    }

    public function compareTo(Comparable $other): int {
        assert($this instanceof $other && $other instanceof $this);

        return $this->value <=> $other->value;
    }

}

$c1 = new C(0);
$c2 = new C(0);

var_dump($c1->compareTo($c2)); // int(0)

$c0 = new C(0);
$c1 = new C(1);
$c2 = new C(2);

$actual = [$c2, $c1, $c0];
usort($actual, 'class_compare');

var_dump($actual === [$c0, $c1, $c2]); // bool(true)

assert非常重要,因为PHP中没有泛型。这是一个相当悲伤的事情,并没有很好的方法来实现这一点。

我倾向于做的是以下内容。

<?php

final class SomeClass {

    private $value;

    public function __construct($value) {
        $this->value = $value;
    }

    public static function compare(SomeClass $a, SomeClass $b): int {
        return $a->compareTo($b);
    }

    public function compareTo(SomeClass $other): int {
        return $this->value <=> $other->value;
    }

    public function isEqual($other): bool {
        return $other instanceof $this && $other->value === $this->value;
    }

    public function isIdentical($other): bool {
        return $other instanceof $this && $this instanceof $other && $other->value === $this->value;
    }

}

按照惯例简单地遵循这些方法名称允许它适当地使用它们。甚至可以提供特征来在多个类中实现所需的默认行为。

答案 3 :(得分:1)

基本上,正如每个人所说,这样做:

$object1 == $object2

比较类型和属性。


但是我在这种情况下做的是,当我想个性化我的等式方法时,在我想要断言相等的类中实现魔术方法__toString()。

class Car {
  private $name;
  private $model;
   ...
  public function __toString() {
     return $this->name.", ".$this->model;
  }
}

然后当我想进行比较时,我就这样做了:

$car1->toString() === $car2->toString()

如果两个实例具有相同的属性,那将进行比较。

另一个选项(作为注释中的halfer状态)实现了一个相等的方法,该方法断言同一个类的另一个实例的相等性。例如:

class Car {
  private $name;
  private $model;
   ...
  public function equals(Car $anotherCar) {
         if($anotherCar->getName() !== $this->name) {
           return false;
         }

         if($anotherCar->getModel() !== $this->model) {
           return false;
         }
         ...
         return true;
  }
}

答案 4 :(得分:0)

如果要比较自定义对象,可以这样做:

$time1 = new MyTimeClass("09:35:12");
$time2 = new MyTimeClass("09:36:09");

if($time1 > $time2) echo "Time1 is bigger";
else echo "Time2 is bigger";

//result: Time1 is bigger

它比较了在类中找到的第一个属性,在我的例子中是一个int值,它保存给定时间内的总秒数。 如果你将$ seconds属性放在最前面,你会注意到它会出现意外的'Time1更大'。

class MyTimeClass {
    public $intValue;
    public $hours;
    public $minutes;
    public $seconds;

    public function __construct($str){
        $array = explode(":",$str);
        $this->hours = $array[0];
        $this->minutes = $array[1];
        $this->seconds = $array[2];
        $this->intValue = ($this->hours * 3600) + ($this->minutes * 60) + $this->seconds;
    }
}