3v4l.org

run code in 300+ PHP versions simultaneously
<?php class Comparator { public static function compareEntities($entityX, $entityY, array $exclusion = []) { if (is_object($entityX) && is_object($entityY)) { return self::checkObjectsEquals($entityX, $entityY, $exclusion); } if (is_array($entityX) && is_array($entityY)) { return self::checkArraysEquals($entityX, $entityY, $exclusion); } return $entityX == $entityY; } public static function checkObjectsEquals($objectX, $objectY, array $exclusion = []) { if (!is_object($objectX) || !is_object($objectY)) { return false; } return self::checkObjectsEqualsByReflection($objectX, $objectY, $exclusion); } public static function checkArraysEquals(array $arrayX, array $arrayY, array $exclusion = []) { return self::checkArraysEqualsByReflection($arrayX, $arrayY, $exclusion); } private static function checkObjectsEqualsByReflection($objectX, $objectY, array $exclusion = [], array &$visitedObjectHashes = []) { if (get_class($objectX) != get_class($objectY)) { return false; } $visitedObjectHashes[] = self::getObjectHash($objectX); $visitedObjectHashes[] = self::getObjectHash($objectY); $reflectionX = new \ReflectionObject($objectX); $reflectionY = new \ReflectionObject($objectY); if (count($reflectionX->getProperties()) != count($reflectionY->getProperties())) { return false; } foreach ($reflectionX->getProperties() as $property) { $property->setAccessible(true); if (!$reflectionY->hasProperty($property->getName())) { return false; } if (!in_array($property->getName(), $exclusion)) { $entityX = $property->getValue($objectX); $entityY = $property->getValue($objectY); if (!($type = self::getPairType($entityX, $entityY))) { return false; } switch ($type) { case 'object' : $alreadyVisited = array_intersect([self::getObjectHash($entityX), self::getObjectHash($entityY)], $visitedObjectHashes); if (!$alreadyVisited && !self::checkObjectsEqualsByReflection($entityX, $entityY, $exclusion, $visitedObjectHashes)) { return false; } break; case 'array' : if (!self::checkArraysEqualsByReflection($entityX, $entityY, $exclusion, $visitedObjectHashes)) { return false; } break; default : if ($entityX != $entityY) { return false; } break; } } } return true; } private static function checkArraysEqualsByReflection(array $arrayX, array $arrayY, array $exclusion = [], array &$visitedObjectHashes = []) { if (count($arrayX) != count($arrayY)) { return false; } $entityY = current($arrayY); foreach ($arrayX as $entityX) { if (!($type = self::getPairType($entityX, $entityY))) { return false; } switch ($type) { case 'object' : $alreadyVisited = array_intersect([self::getObjectHash($entityX), self::getObjectHash($entityY)], $visitedObjectHashes); if (!$alreadyVisited && !self::checkObjectsEqualsByReflection($entityX, $entityY, $exclusion, $visitedObjectHashes)) { return false; } break; case 'array' : if (!self::checkArraysEqualsByReflection($entityX, $entityY, $exclusion, $visitedObjectHashes)) { return false; } break; default : if ($entityX != $entityY) { return false; } break; } $entityY = next($arrayY); } return true; } private static function getObjectHash($object) { return spl_object_hash($object); } private static function getPairType($entityX, $entityY) { if (gettype($entityX) != gettype($entityY)) { return null; } return gettype($entityX); } } class Foo { private $holder; private $children; public function __construct($content = '', array $children = []) { $this->holder = $content; $this->setChildren($children); } public function setChildren(array $children) { $this->children = $children; foreach ($children as $child) { $child->setParent($this); } } } class Bar { private $holder; private $parent; public function __construct($content = '', Foo $parent = null) { $this->holder = $content; $this->setParent($parent); } public function setParent(Foo $parent = null) { $this->parent = $parent; } } $child0 = new Bar('child#0'); $child1 = new Bar('child#1'); //same $child2 = new Bar('child#0'); $child3 = new Bar('child#1'); $parent0 = new Foo('parent', [$child0, $child1]); $parent1 = new Foo('parent', [$child2, $child3]); //Valid: var_dump(Comparator::compareEntities($parent0, $parent1));
Output for 5.4.0 - 5.4.45, 5.5.0 - 5.5.36, 5.6.0 - 5.6.28, 7.0.0 - 7.0.20, 7.1.0 - 7.1.25, 7.2.0 - 7.2.33, 7.3.0 - 7.3.33, 7.4.0 - 7.4.33, 8.0.0 - 8.0.30, 8.1.0 - 8.1.28, 8.2.0 - 8.2.18, 8.3.0 - 8.3.6
bool(true)

preferences:
231.57 ms | 404 KiB | 276 Q