Подтвердить что ты не робот

Есть ли метод __equals в PHP, как в Java?

Есть ли шаблон или магический метод, который вы можете использовать в PHP, чтобы определить, когда сравнивать два экземпляра класса?

Например, в Java я мог бы легко переопределить метод equals и создать собственный способ проверки и сравнения двух экземпляров.

4b9b3361

Ответ 1

Одним словом? Нет. Нет магического метода __equals. Существует полный список магических методов в руководстве.

Вы можете сделать

$myObject1 == $myObject2

которые будут считать их равными, если они имеют одинаковые атрибуты и значения, и являются экземплярами одного и того же класса.

Я часто хотел, чтобы этот тип метода был сам, но я думаю, что более полезным будет метод __compare(), который будет вызываться для любого оператора сравнения <, > , ==, === и т.д. он уже существует для встроенных классов PHP, как можно увидеть в внутренней вики PHP, и есть пример того, как он может быть реализован в Книга PHPInternals: -

compare_objects

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

Сравнивает два объекта. Используется для операторов ==,! =, <, > , ⇐ и > =. Реализации должны следовать этим правилам - для любых объектов a, b и c, которые используют один и тот же обработчик сравнения:

Один из способов, который я использовал для этого, - реализовать интерфейс Comparable, например: -

interface Comparable
{
    /**
     * @param Comparable $other
     * @param String $comparison any of ==, <, >, =<, >=, etc
     * @return Bool true | false depending on result of comparison
     */
    public function compareTo(Comparable $other, $comparison);
}

Детали сопоставления объектов и все остальное ООП можно найти здесь http://www.php.net/manual/en/language.oop5.php.

Это может быть реализовано в PHP 7.

Ответ 2

К сожалению, нет, но вы можете легко воспроизвести что-то близкое. Например: -

<?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

Это не особенно элегантно, но должно помочь вам.

Энтони.

Ответ 3

В большинстве случаев оператор == достаточен, особенно если речь идет о объектах значений. Просто не забудьте предоставить метод __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), потому что он будет жаловаться, что экземпляр не может быть преобразован в желаемое значение. Следовательно, вам всегда нужно убедиться, что тип значения, с которым вы сравниваете, представляет собой строку.

Если вы хотите больше, например, вы хотите, чтобы ввести значение ввода или обрабатывать значение float до определенной точности, вам нужен другой подход. Один из способов справиться с этим состоит в следующем.

<?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;
    }

}

Просто придерживаясь этих имен методов по соглашению, вы можете использовать их соответствующим образом. Можно даже представить черты для реализации желаемого поведения по умолчанию для нескольких классов.

Ответ 4

В принципе, как все говорят, это будет делать:

$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;
  }
}

Ответ 5

Если вы хотите сравнить свой пользовательский объект, вы можете сделать это следующим образом:

$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;
    }
}