Cómo comparar objectos en PHP

PHP ofrece una manera sencilla de comparar objectos usando los operadores de comparación (==) e identidad (===), si usamos el operador de comparación entonces los objetos son comparados en forma simple o sea 2 objectos son iguales si son instancias de la misma clase y tienen los mismos atributos (propiedades) y valores, si usamos el operador de identidad entonces 2 objetos son iguales solo si hacen referencia (o apuntan) a la misma instancia de la misma clase.

En ocaciones no basta con saber si 2 objetos son iguales o differentes sino que en el caso de que sean differentes necesitamos saber las differencias, podemos lograrlo creando una función que reciba como parámetros los objetos a comparar, obtenga las propiedades de los objetos usando Reflection itere por las propiedades de los objetos y compare los valores de las propiedades y luego retorne un arreglo con las differencias.

Pongamos lo comentado anteriormente en la siguiente clase:

<?php
namespace Comparator;

use ReflectionObject;
use InvalidArgumentException;

class ObjectComparator
{

    /**
     * Compare 2 objects
     *
     * @param $o1
     * @param $o2
     * @param $strict Compare in simple (==) or in strict way (===)
     * @return true objects are equals, false objects are differents
     */
    public static function equal($o1, $o2, $strict = false)
    {
        return $strict ? $o1 === $o2 : $o1 == $o2;
    }

    /**
     * Find the differences between 2 objects using Reflection.
     *
     * @param $o1
     * @param $o2
     * @return array Properties that have changed
     * @throws InvalidArgumentException
     */
    public static function diff($o1, $o2)
    {
        if (!is_object($o1) || !is_object($o2)) {
            throw new InvalidArgumentException("Parameters should be of object type!");
        }

        $diff = [];
        if (get_class($o1) == get_class($o2)) {
            $o1Properties = (new ReflectionObject($o1))->getProperties();
            $o2Reflected = new ReflectionObject($o2);

            foreach ($o1Properties as $o1Property) {
                $o2Property = $o2Reflected->getProperty($o1Property->getName());
                // Mark private properties as accessible only for reflected class
                $o1Property->setAccessible(true);
                $o2Property->setAccessible(true);
                if (($oldValue = $o1Property->getValue($o1)) != ($newValue = $o2Property->getValue($o2))) {
                    $diff[$o1Property->getName()] = [
                        'old_value' => $oldValue,
                        'new_value' => $newValue
                    ];
                }
            }
        }

        return $diff;
    }
}

Realizando algunas pruebas

<?php
include __DIR__ . '/ObjectComparator.php';

use Comparator\ObjectComparator as Comparator;

class Person
{
    public $name = '';
    private $age = 0;

    public function setAge($age)
    {
        $this->age = $age;
    }
}

function print_ln() {
    return php_sapi_name() == 'cli' ? PHP_EOL : nl2br(PHP_EOL);
}

$p1 = new Person();
$p2 = new Person();


echo '1. p1 == p2 => ', Comparator::equal($p1, $p2) ? 'Yes' : 'No', print_ln(); // Print Yes

$p1->name = 'Juan';

echo '2. p1 == p2 => ', Comparator::equal($p1, $p2) ? 'Yes' : 'No', print_ln();  // Print No

$p2->name = 'Juan';

echo '3. p1 == p2 => ', Comparator::equal($p1, $p2) ? 'Yes' : 'No', print_ln(); // Print Yes

$p2->setAge(20);

echo '4. p1 == p2 => ', Comparator::equal($p1, $p2) ? 'Yes' : 'No', print_ln(); // Print No

$p1->setAge(20);

echo '5. p1 == p2 => ', Comparator::equal($p1, $p2) ? 'Yes' : 'No', print_ln(); // Print Yes

$p2 = clone $p1;
echo '6. p1 == p2 => ', Comparator::equal($p1, $p2, true) ? 'Yes' : 'No', print_ln(); // Print No

$p2 = $p1;
echo '7. p1 == p2 => ', Comparator::equal($p1, $p2, true) ? 'Yes' : 'No', print_ln(); // Print Yes

$p3 = new Person();
$p3->name = 'Pepe';
$p3->setAge(50);

echo '8. Get the differences for p1, p3', print_ln();
foreach (Comparator::diff($p1, $p3) as $property => $diff) {
    echo $property, ' => ', 'old value: ', $diff['old_value'], ', new value: ', $diff['new_value'], print_ln();
}

// Print
// Get the differences for p1, p3
// name => old value: Juan, new value: Pepe
// age => old value: 20, new value: 50

Lecturas recomendadas


YouTube video
Los tutoriales aquí en LibreByte están disponible bajo una licencia de software libre. Si le gusta mi trabajo considere:
Comprar un Hosting/VPS o Servidor Dedicado en MCKHost

Deja una respuesta

Tu dirección de correo electrónico no será publicada.

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.