PHP 中是否有 __equals 方法,就像 Java 中一样?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17008622/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is there a __equals method in PHP like there is in Java?
提问by Simon
Is there a pattern or magic method you can use in PHP to define when to compare two instances of a class?
是否有可以在 PHP 中使用的模式或魔术方法来定义何时比较一个类的两个实例?
For example, in Java I could easily override the equals
method and create a custom way of checking and compare two instances.
例如,在 Java 中,我可以轻松地覆盖该equals
方法并创建一种自定义方式来检查和比较两个实例。
采纳答案by vascowhite
In a word? No. There is no __equals
magic method. There is a complete list of the magic methods in the manual.
一句话?不,没有__equals
神奇的方法。有神奇的方法的完整列表在手册中。
You can do
你可以做
$myObject1 == $myObject2
which will consider them equal if they have the same attributes and values, and are instances of the same class.
如果它们具有相同的属性和值,并且是同一类的实例,则将它们视为相等。
I have often wished for this type of method myself, but I think that a more useful one would be a __compare()
method which would be called for any comparison operator <, >, ==, ===, etc it already exist for PHP's inbuilt classes as can be seen in the PHP internals wikiand there is an example of how it could be implemented in the PHPInternals book:-
我自己经常希望使用这种类型的方法,但我认为更有用的__compare()
方法是可以为任何比较运算符 <、>、==、=== 等调用的方法,它已经存在于 PHP 的内置类中正如在PHP internals wiki 中所见,在PHPInternals 书中有一个示例说明如何实现它:-
compare_objects
int (*compare)(zval *object1, zval *object2 TSRMLS_DC)
Compares two objects. Used for the operators ==, !=, <, >, ? and >=. The implementations should follow these rules – for any objects a, b and c that share the same compare handler:
比较对象
int (*compare)(zval *object1, zval *object2 TSRMLS_DC)
比较两个对象。用于运算符 ==、!=、<、>、? 并且 >=。实现应该遵循这些规则——对于共享相同比较处理程序的任何对象 a、b 和 c:
One way I have used to achieve this is to implement a Comparable interface, something like:-
我用来实现这一目标的一种方法是实现一个 Comparable 接口,例如:-
interface Comparable
{
/**
* @param Comparable $other
*
* @return Int -1, 0 or 1 Depending on result of comparison
*/
public function compareTo(Comparable $other);
}
The details of object comparison, and everything else OOP related can be found here http://www.php.net/manual/en/language.oop5.php.
对象比较的详细信息以及与 OOP 相关的所有其他内容都可以在这里找到http://www.php.net/manual/en/language.oop5.php。
This may be implemented in PHP 7.
There is now an implementation of this that you can install using composer. https://github.com/Fleshgrinder/php-comparable
现在有一个可以使用 composer 安装的实现。https://github.com/Fleshgrinder/php-comparable
回答by Anthony Sterling
Sadly not, but you can quite easily replicate something close. For example:-
遗憾的是不是,但你可以很容易地复制接近的东西。例如:-
<?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
It's not particularly elegant, but should get you on your way.
它不是特别优雅,但应该让你上路。
Anthony.
安东尼。
回答by Fleshgrinder
First off the ==
operator is sufficient in most cases, especially if we are talking about value objects. Just be sure to provide a __toString
method if you want the ability to compare the instance with scalar values.
==
在大多数情况下,首先运算符就足够了,尤其是当我们谈论值对象时。__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)
);
There is one gotcha with this, you cannot compare to scalar type other than string (at least not in PHP 5 and 7) because it will complain that the instance could not be converted to the desired value. Hence, you always need to ensure that the value type you compare to is a string.
这有一个问题,您不能与字符串以外的标量类型进行比较(至少在 PHP 5 和 7 中不是),因为它会抱怨实例无法转换为所需的值。因此,您始终需要确保您比较的值类型是字符串。
If you want more than that, e.g. you want to lowercase the input or handle float value up until a certain accuracy, you need a different approach. One way to handle this is as follows.
如果您想要更多,例如您想小写输入或处理浮点值直到达到一定的精度,您需要一种不同的方法。处理此问题的一种方法如下。
<?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)
The assert
is important since we have no generics in PHP. This is a pretty sad state of things and there is no pretty way to implement this.
这assert
很重要,因为我们在 PHP 中没有泛型。这是一个非常可悲的状态,没有很好的方法来实现这一点。
What I tend to do is the following.
我倾向于做的是以下。
<?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;
}
}
Simply sticking to these method names by convention allows it to use them appropriately. One could even provide traits to implement the desired default behavior among multiple classes.
只需按照惯例坚持使用这些方法名称,就可以适当地使用它们。甚至可以提供特性来在多个类中实现所需的默认行为。
回答by Tomas Prado
Basically, as everyone says, this will do:
基本上,正如每个人所说,这将做到:
$object1 == $object2
Compares type and properties.
比较类型和属性。
But what I do in this cases, when I want to personalize my equality methods, is implement the magic method __toString() in the classes I want to assert equality.
但是在这种情况下,当我想要个性化我的相等方法时,我所做的是在要断言相等的类中实现魔术方法 __toString()。
class Car {
private $name;
private $model;
...
public function __toString() {
return $this->name.", ".$this->model;
}
}
And then when I want to do the comparision I just do this:
然后当我想做比较时,我就这样做:
$car1->toString() === $car2->toString()
And that will compare if the two instances have the same attributes.
这将比较两个实例是否具有相同的属性。
The other option (as halfer states in the comments) is implement an equal method that asserts equality of another instance of the same class. For example:
另一个选项(如评论中的 halfer 状态)是实现一个 equal 方法,该方法断言同一类的另一个实例的相等性。例如:
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;
}
}
回答by Johan Velthuis
If you want to compare your custom object, you can do it like this:
如果要比较自定义对象,可以这样做:
$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
It compares the first property found in the class, in my case an int value that holds the total number of seconds in the given time. If you put the $seconds property on top you'll notice that it gives an unexpected '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;
}
}