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

Может ли функция in_array сравнивать объекты?

Например, у меня есть массив объектов, и я хочу добавить их к другому массиву. Можно ли проверить, был ли объект уже добавлен так:

in_array($distinct, $object);

или есть ли другой способ?

Ответ 1

Функция in_array не может сравнивать объекты.

Вам необходимо создать уникальные пары ключ-значение из ваших объектов и только сравнить эти ключи при вставке нового объекта в ваш окончательный массив.

Предполагая, что каждый объект имеет уникальное свойство id, возможным решением будет следующее:

$unique_objects = array();

// $data represents your object collection
foreach ($data as $item) {
    if (!array_key_exists($item->id, $unique_objects)) {
        $unique_objects[$item->id] = $obj;
    }
}

Ответ 2

Вы можете использовать строгое сравнение:

in_array($object, $array, TRUE);

Пример использования:

$a = new stdClass();
$a->x = 42;

$b = new stdClass();
$b->y = 42;

$c = new stdClass();
$c->x = 42;

$array = array($a,$b);

echo in_array($a, $array, true); // 1
echo in_array($b, $array, true); // 1
echo in_array($c, $array, true); //

Ответ 4

Существует множество способов сделать это, как вы можете видеть. Я просто подумал, что добавлю еще один. Я не знаю почему, но при работе с объектными массивами мне нравится использовать функции массива, которые используют обратные вызовы.

Если у ваших объектов есть какой-либо идентификатор, который они должны, если вы хотите проверить их для дублирования, будет работать следующее:

$found = array_filter($uniqueObjects, function($uniqueObject) use ($object) {
    return $uniqueObject->id == $object->id
});

if (!$found) {
    $uniqueObjects[] = $object;
}

$object - объект, который вы ищете, и $uniqueObjects - это массив объектов, которые вы ищете, чтобы увидеть, существует ли он. Просто сопоставьте uniqueObject и объект с идентификационным свойством, например id.

Ответ 5

Я не знаю, связано ли это с новой версией PHP, но в моем проекте, используя PHP 5.3.16 на Ubuntu 12.04, это сработало. Он нашел объект иглы в моем массиве объектов. Я также дважды проверял загрузку другого объекта того же класса и тестирование его на содержимое массива, которое не содержало этот объект, и оно действительно верно вернулось.

Итак, да, in_array может сравнивать объекты.

Ответ 6

Если "STRICT" является "FALSE", сравнение производится путем преобразования в строку элементов. Поэтому, если вы переопределите магическую функцию __toString, вы должны быть доступны для сравнения элементов объектов.

Ответ 7

Я придумал несколько другое, я думаю, более надежный вариант.

function array_add_unique(&$array, $new, $test, $cb) {
  if(is_array($array) && count($array)>0) {
    for($i = 0; $i < count($array); $i++) {
      if( $array[$i][$test] == $new[$test] ) {
        $do = $cb($array[$i], $new);
        if(is_bool($do) && $do) { $array[$i] = $new; }
        else if(!is_bool($do)) { $array[$i] = $do; }
        return;
      }
    }
  }
  array_push($array, $new);
}

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

Обратный вызов, который может быть анонимной функцией, получает как новый объект, так и существующий объект, поэтому пользователь может иметь собственный расчет. Верните true, чтобы просто заменить существующий объект или вернуть новый объект (non-bool), чтобы заменить его.

Я не знаю, как это работает на больших наборах данных.

Ответ 8

Я провел несколько тестов со сравнением объектов с помощью функции in_array. Это мой вывод:

Когда вы пытаетесь найти тот же экземпляр объекта в массиве (например, OP), тогда in_array может работать с логическим набором строгого сравнения.

Когда вы пытаетесь найти какой-либо объект того же класса, но с другим экземпляром, in_array демонстрирует нелогичное поведение.

На PHP.net есть замечательный пользовательский комментарий о нелогичных крайних случаях.

// Example array

$array = array(
    'egg' => true,
    'cheese' => false,
    'hair' => 765,
    'goblins' => null,
    'ogres' => 'no ogres allowed in this array'
);

// Loose checking -- return values are in comments

// First three make sense, last four do not

in_array(null, $array); // true
in_array(false, $array); // true
in_array(765, $array); // true
in_array(763, $array); // true
in_array('egg', $array); // true
in_array('hhh', $array); // true
in_array(array(), $array); // true

// Strict checking

in_array(null, $array, true); // true
in_array(false, $array, true); // true
in_array(765, $array, true); // true
in_array(763, $array, true); // false
in_array('egg', $array, true); // false
in_array('hhh', $array, true); // false
in_array(array(), $array, true); // false

Как видите, без строгой проверки тесты in_array не имеют смысла.

Мы знаем из PHP.net, что два объекта одинаковы при строгом сравнении (===), если они принадлежат одному и тому же классу + экземпляру. Два объекта уже одинаковы в произвольном сравнении (==), когда они принадлежат к одному и тому же классу.

Я написал несколько тестов с объектами, чтобы увидеть, что происходит.

$a = new stdClass();                              
$a->egg = true;                                   

$b = new stdClass();                              
$b->cheese = false;                               

$c = new stdClass();                              
$c->hair = 765;                                   

$d = new stdClass();                              
$d->goblins = null;                               

$e = new stdClass();                              
$e->ogres = 'no ogres allowed in this array';     

$array2 = array($a, $b, $c,  $d, $e);         

$e = new stdClass();                                            
$e->egg = null;                                                 

$f = new stdClass();                                            
$f->egg = false;                                                

$g = new stdClass();                                            
$g->egg = 765;                                                  

$h = new stdClass();                                            
$h->egg = 763;                                                  

$i = new stdClass();                                            
$i->egg = 'egg';                                                

$j = new stdClass();                                            
$j->egg = 'hhh';                                                

$k = new stdClass();                                            
$k->egg = array();                                              

in_array($e, $array2, false); // false                
in_array($f, $array2, false); // false                
in_array($g, $array2, false); // true                 
in_array($h, $array2, false); // true                 
in_array($i, $array2, false); // true                 
in_array($j, $array2, false); // true                 
in_array($k, $array2, false); // false                

in_array($e, $array2, true); // false                 
in_array($f, $array2, true); // false                 
in_array($g, $array2, true); // false                 
in_array($h, $array2, true); // false                 
in_array($i, $array2, true); // false                 
in_array($j, $array2, true); // false                 
in_array($k, $array2, true); // false 

В последних проверках проверки in_array 3 - 6 дают нелогичные результаты.

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