PHP in_array object comparing?

后端 未结 8 1159
终归单人心
终归单人心 2020-12-17 08:37

Can the in_array function compare objects?

For example, I have an array of objects and I want to add them distinctly to another array. Is it possible t

相关标签:
8条回答
  • 2020-12-17 09:20

    I've come up with a somewhat different, I think more robust, option.

    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);
    }
    

    The benefit to this solution, is it includes a user definable callback to handle collisions. When your adding unique objects, you may want to preserve properties from both the old and the new object.

    The callback, which can be an anonymous function, receives both the new object and the existing object so the user can have a custom calculation. Return true to simply replace the existing object, or return a new object (non-bool) to replace it.

    I do not know the performance of this on large datasets though.

    0 讨论(0)
  • 2020-12-17 09:21

    The in_array function cannot compare objects.

    You should create unique key-value pairs from your objects and only need to compare those keys when inserting a new object into your final array.

    Assuming that each object has an unique id property, a possible solution would be:

    $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;
        }
    }
    
    0 讨论(0)
  • 2020-12-17 09:28

    I don't know if it is because of a newer PHP version, but in my project, using PHP 5.3.16 on Ubuntu 12.04, it worked. It found the needle object in my array of objects. I have also double-checked by loading a different object of the same class, and testing it against the array contents which did not contain that object, and it returned false indeed.

    So yes, in_array can compare objects.

    0 讨论(0)
  • 2020-12-17 09:36

    You can use strict comparison:

    in_array($object, $array, TRUE);
    

    Usage example:

    $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); //
    
    0 讨论(0)
  • 2020-12-17 09:36

    If "STRICT" is "FALSE", the comparison is made by converting in a string the elements. So if you override the __toString magic function, you should be available to compare the objects elements.

    0 讨论(0)
  • 2020-12-17 09:39

    I did some tests comparing objects with the in_array function. This is my conclusion:

    When you try to find the same instance of an object in an array (like OP), then in_array could work with the strict comparison boolean set.

    When you try to find any object of the same class but with a different instance, in_array shows counter-intuitive behavior.

    There is a great user comment on PHP.net about the counter-intuitive edge cases.

    // 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
    

    As you can see that without strict checking the in_array tests 4 - 7 don't make sense.

    We know from PHP.net that two objects are only the same in strict comparison (===) when they are from the same class + instance. Two objects are already the same in loose comparison (==) when they are from the same class.

    I wrote some tests with objects to see what happens.

    $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 the last checks in_array checks 3 - 6 give counter-intuitive results.

    The reason is as follow. If you try to find any object with a certain value, you are forced to use loose comparison (because when the class is not the same, strict comparison always fails). But due to PHP's variable types, in the last tests these checks are considered true, because the value is considered truthy. Also note that the key on the object is ignored in loose comparison.

    0 讨论(0)
提交回复
热议问题