Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find differences between two arrays of objects where the comparison is upon the return value of a method call

I have got a problem with PHP function array_diff().

In both cases I'm using it on arrays of the same class objects.

First case:

public function findFreeUsers($weekId)
{
    $em = $this->getEntityManager();
    $week = $em->getRepository(Week::class)->findOneBy(["id" => $weekId]);
    $busyWeeks = $em->getRepository(Week::class)->findWeekBetweenDates($week);
    $busyUsers = array();
    foreach ($busyWeeks AS $busyWeek) {
        $tmp = $em->getRepository(UserWeek::class)->findBy(["week" => $busyWeek["id"]]);
        if ($tmp != null) {
            foreach($tmp AS $singleWeek) {
                $busyUsers[] = $singleWeek->getUser();
            }
        }
    }
    $allUsers = $em->getRepository(User::class)->findAll();
    $freeUsers = array_diff($allUsers, $busyUsers);
    return $freeUsers;
}

Second case:

public function findFreeCars($weekId)
{
    $em = $this->getEntityManager();
    $week = $em->getRepository(Week::class)->findOneBy(["id" => $weekId]);
    $busyWeeks = $em->getRepository(Week::class)->findWeekBetweenDates($week);
    $busyCars = array();
    foreach ($busyWeeks AS $busyWeek) {
        $tmp = $em->getRepository(CarWeek::class)->findBy(["week" => $busyWeek["id"]]);
        if ($tmp != null) {
            foreach($tmp AS $singleWeek) {
                $busyCars[] = $singleWeek->getCar();
            }
        }
    }
    $allCars = $em->getRepository(Car::class)->findAll();
    $freeCars = array_diff($allCars, $busyCars);
    return $freeCars;
}

I'm dumping these arrays and all of them are arrays with objects of the same class.

In first case it works, in second I've got:

Error: Object of class AppBundle\Entity\Car could not be converted to string

like image 939
Maciej Kuliński Avatar asked Dec 10 '25 15:12

Maciej Kuliński


1 Answers

You shouldn't use array_diff to compare the arrays with objects.

To do it properly you need to use array_udiff() and you need to define what "difference" between objects means.

For example objects may be different if they have different id

function compareCars(Car $objA, Car $objB) {
  return $objA->getId() <=> $objB->getId();
}

$diff = array_udiff($allCars, $busyCars, 'compareCars')

If you added for example ComparableInterface to every class that you want to compare via id with just one method getId() then you could use the benefits of polymorphism

interface ComparableInterface
{
   public function getId();
}


class Car implements ComparableInterface
{
    public function getId()
    {
       return $this->id;
    }
    //rest of the class source 
}

function compareCars(ComparableInterface $objA, ComparableInterface $objB) {
   return $objA->getId() <=> $objB->getId();
}

or even define compare() method that returns for every object if it's equal or not

interface AdvancedComparableInterface extends ComparableInterface
{
   public function compare(ComparableInterface $obj);
}

class Car implements AdvancedComparableInterface
{
    public function getId()
    {
       return $this->id;
    }

    public function compare(ComparableInterface $obj)
    {
       return $this->getId() <=> $obj->getId();
    }
    //rest of the class source 
}

function compareCars(AdvancedComparableInterface $objA, ComparableInterface $objB) {
   return $objA->compare($objB);
}

As you see you can use multiple ways of defining if the object is the same as the other one. For example the cars you could be compared by VIN

Side note:

Executing the queries in a loop is a bad idea in terms of doctrine's performance. It's be better if you make one query by passing ids of busyWeek as array to findBy method.

like image 134
Robert Avatar answered Dec 13 '25 07:12

Robert



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!