тк 3 июля праздник (в беларуси), буду не онлайн (по возможности буду отвечать)

Сравнение объектов

Сейчас мы с вами научимся сравнивать объекты с помощью операторов == и ===.

Вы должны уже знать, что для примитивов (то есть не объектов) оператор == сравнивает данные по значению без учета типа, а оператор === - учитывая тип:

<?php var_dump(3 == 3); // выведет true var_dump(3 == '3'); // выведет true var_dump(3 === 3); // выведет true var_dump(3 === '3'); // выведет false ?>

Давайте теперь посмотрим, как работает сравнение объектов.

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

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

Давайте посмотрим на примере. Пусть у нас дан вот такой класс User:

<?php class User { private $name; private $age; public function __construct($name, $age) { $this->name = $name; $this->age = $age; } public function getName() { return $this->name; } public function getAge() { return $this->age; } } ?>

Создадим два объекта нашего класса с одинаковыми значениями свойств и сравним созданные объекты:

<?php $user1 = new User('Коля', 30); $user2 = new User('Коля', 30); var_dump($user1 == $user2); // выведет true ?>

Пусть теперь значения свойств одинаковые, но у них разный тип:

<?php $user1 = new User('Коля', 30); // возраст - число $user2 = new User('Коля', '30'); // возраст - строка var_dump($user1 == $user2); // выведет true ?>

Пусть значения свойств разные:

<?php $user1 = new User('Коля', 30); $user2 = new User('Коля', 25); var_dump($user1 == $user2); // выведет false ?>

Давайте теперь сравним два наших объекта через ===:

<?php $user1 = new User('Коля', 30); $user2 = new User('Коля', 30); var_dump($user1 === $user2); // выведет false ?>

Чтобы две переменных с объектами действительно были равными при сравнении через ===, они должны указывать на один и тот же объект.

Давайте сделаем, чтобы это было так, и сравним переменные:

<?php $user1 = new User('Коля', 30); $user2 = $user1; // передача объекта по ссылке var_dump($user1 === $user1); // выведет true ?>

Сделайте функцию compare, которая параметром будет принимать два объекта и возвращать true, если они имеют одинаковые свойства и значения являются экземплярами одного и того же класса, и false, если это не так.

Сделайте функцию compare, которая параметром будет принимать два объекта и возвращать true, если переданные переменные ссылаются на один и тот же объект, и false, если на разные.

Сделайте функцию compare, которая параметром будет принимать два объекта и сравнивать их.

Функция должна возвращать 1, если переданные переменные ссылаются на один и тот же объект.

Функция должна возвращать 0, если объекты разные, но одного и того же класса и с теми же свойствами и их значениями.

Функция должна возвращать -1 в противном случае.

Применение

Давайте рассмотрим применение изученной теории.

Пусть у нас дан вот такой класс Employee:

<?php class Employee { private $name; private $salary; public function __construct($name, $salary) { $this->name = $name; $this->salary = $salary; } public function getName() { return $this->name; } public function getSalary() { return $this->salary; } } ?>

Пусть также дан такой класс EmployeesCollection для хранения коллекции работников:

<?php class EmployeesCollection { private $employees = []; // массив работников // Добавляем нового работника: public function add($newEmployee) { $this->employees[] = $newEmployee; } // Получаем всех работников в виде массива: public function get() { return $this->employees; } } ?>

Давайте сделаем так, чтобы работник, который уже есть в нашем наборе, не добавлялся еще раз.

Для этого сделаем вспомогательный метод exists, который будет принимать объект с новым работником и проверять его наличие в массиве $this->employees:

<?php private function exists($newEmployee) { foreach ($this->employees as $employee) { if ($employee == $newEmployee) { // сравниваем через == return true; } } return false; } ?>

Давайте применим новый метод в нашем классе:

<?php class EmployeesCollection { private $employees = []; public function add($newEmployee) { // Если такого работника нет - то добавляем: if (!$this->exists($newEmployee)) { $this->employees[] = $newEmployee; } } public function get() { return $this->employees; } private function exists($newEmployee) { foreach ($this->employees as $employee) { if ($employee == $newEmployee) { return true; } } return false; } } ?>

Давайте проверим работу нашего класса:

<?php $employeesCollection = new EmployeesCollection; $employeesCollection->add(new Employee('Коля', 100)); $employeesCollection->add(new Employee('Коля', 100)); // второго такого же не добавит var_dump($employeesCollection->get()); // убедимся в этом ?>

В общем-то, мы получили устраивающий нас код. Но давайте попробуем поиграться с ним: поменяем при сравнении двойное равно на тройное:

<?php private function exists($newEmployee) { foreach ($this->products as $product) { if ($product === $newEmployee) { //!! сравниваем через === return true; } } return false; } ?>

Теперь при попытке добавить нового работника с такими же значениями свойств он будет добавляться:

<?php $employeesCollection = new EmployeesCollection; $employeesCollection->add(new Employee('Коля', 100)); $employeesCollection->add(new Employee('Коля', 100)); // добавит var_dump($employeesCollection->get()); ?>

Но если попытаться добавить тот же объект, то добавления не произойдет:

<?php $employeesCollection = new EmployeesCollection; $employee = new Employee('Коля', 100); $employeesCollection->add($employee); $employeesCollection->add($employee); // не добавит, тк тот же объект var_dump($employeesCollection->get()); ?>

Скопируйте мой код класса Employee, затем самостоятельно реализуйте описанный класс EmployeesCollection, проверьте его работу.

Функция in_array

На самом деле код функции exists можно заменить стандартной PHP функцией in_array.

Нужно только знать, как она выполняет сравнение - по двойному равно или по тройному.

Из документации следует, что функция in_array имеет третий необязательный параметр. Если он не установлен или равен false - функция сравнивает по двойному равно, а равен true - то по тройному.

Давайте упростим код класса при условии сравнения объектов через двойное равно:

<?php class EmployeesCollection { private $employees = []; public function add($newEmployee) { if (!in_array($newEmployee, $this->employees, false)) { $this->employees[] = $newEmployee; } } public function get() { return $this->employees; } } ?>

А теперь при условии сравнения на тройное равно:

<?php class EmployeesCollection { private $employees = []; public function add($newEmployee) { // Эквивалентно методу exists с === if (!in_array($newEmployee, $this->employees, true)) { $this->employees[] = $newEmployee; } } public function get() { return $this->employees; } } ?>

Упростите ваш класс EmployeesCollection с использованием функции in_array, проверьте его работу.