Skip to content

Instantly share code, notes, and snippets.

@almadomundo
Created February 6, 2015 08:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save almadomundo/0ec0dce7f5435368aec0 to your computer and use it in GitHub Desktop.
Save almadomundo/0ec0dce7f5435368aec0 to your computer and use it in GitHub Desktop.
<?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));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment