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

Особенности

Во-первых, определение "равенства" в моем случае - это то, что объекты равны, когда у них одинаковая структура и значения для этой структуры. Однако они могут быть не одним и тем же экземпляром, или свойства могут быть не в одном "порядке" (я имею в виду, поскольку они были назначены/определены). Здесь есть похожие вопросы, например , но они не охватывают мое дело.

Мне нужно сравнить объекты в PHP из-за тестирования моих кодовых целей - и эти объекты могут быть чем угодно. В частности, они могут быть объектами. Сравнение объектов, однако, не является "безопасным". Представьте, что вы сравниваете:

$result = $objectX == $objectY;

И это может привести к фатальной ошибке в случае, если объекты имеют круглые ссылки. Простой пример для этого я подготовил здесь. Как мы видим, PHP пытается следовать за вложенными уровнями и терпеть неудачу в бесконечном цикле - потому что объекты природы одинаковы по содержанию, но имеют круглые ссылки.

Важная информация заключается в том, что объекты могут содержать несериализуемые материалы (например, закрытие), что делает невозможным полагаться на подход "серализовать/неэтериализовать" (даже если забыть о неупорядоченном сравнении)

Текущий подход

У меня есть код, например this (довольно много, чтобы вставить прямо здесь, но на всякий случай, вот gist) - так что я выполняю DFS и обнаруживая ситуации с такими круговыми ссылками. Как вы можете видеть, это довольно сложно - и, кстати, оно медленное.

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

И, кроме того, ссылки на круговые массивы также вызовут сбой:

$array = ['foo', $object, &$array];

Вопрос

Какие могут быть другие (лучшие) подходы к решению вопроса? Сериализация объектов может иметь место, но из-за не упорядоченного набора свойств это не удастся для меня.

Ответ 1

Знаете ли вы Doctrine\Common\Util\Debug:: export ($ class, $maxDepth)?

Этот метод "export" предотвращает вас от бесконечного цикла и возвращает массив, который может использоваться для создания diff.

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