tags:

views:

102

answers:

7

What is an elegant way to remove an object from an array of objects in PHP ?

Just to be clear ..

class Data{

  private $arrObservers;

  public add(Observer $o) {  
    array_push($this->arrObservers,$o);  
  }    
  public remove($Observer $o) {  
    // I NEED THIS CODE to remove the object  
  }  

}
+2  A: 

unset($myArray[$index]); where $index is the index of the element you want to remove. If you wan't a more specific answer, show some code or describe what you're trying to do.

Tatu Ulmanen
This is ok ,but How do I find the index of an object? Search by values in the array ?
@daniphp You can compar objects with ===.
Richard Knop
+3  A: 
$obj_array['obj1'] = $obj1;
$obj_array['obj2'] = $obj2;
$obj_array['obj3'] = $obj3;
unset($obj_array['obj3']);
Alexander.Plutov
-1 because OP gives object to the function, not the key and hence this example is incomplete.
Mikulas Dite
+3  A: 

I recommend using the ID (if you have one, anything that will be unique to that object should work within reason) of the object as the array key. This way you can address the object within the array without having to run through a loop or store the ID in another location. The code would look something like this:

$obj_array[$obj1->getId()] = $obj1;
$obj_array[$obj2->getId()] = $obj2;
$obj_array[$obj3->getId()] = $obj3;

unset($obj_array[$object_id]);

UPDATE:

class Data{

  private $arrObservers;

  public add(Observer $o) {  
    $this->arrObservers[$o->getId()] = $o;  
  }    
  public remove(Observer $o) {  
    unset($this->arrObservers[$o->getId()]);
  }  

}
Cody Snider
You will need a getId() method for the Observer object, though.
Cody Snider
+7  A: 

You can do

function unsetValue(array $array, $value, $strict = TRUE)
{
    if(($key = array_search($value, $array, $strict)) !== FALSE) {
        unset($array[$key]);
    }
    return $array;
}

You can also use spl_object_hash to create a hash for the objects and use that as array key.

However, PHP also has a native Data Structure for Object collections with SplObjectStorage:

$a = new StdClass; $a->id = 1;
$b = new StdClass; $b->id = 2;
$c = new StdClass; $c->id = 3;

$storage = new SplObjectStorage;
$storage->attach($a);
$storage->attach($b);
$storage->attach($c);
echo $storage->count(); // 3

// trying to attach same object again
$storage->attach($c);
echo $storage->count(); // still 3

var_dump( $storage->contains($b) ); // TRUE
$storage->detach($b);
var_dump( $storage->contains($b) ); // FALSE

SplObjectStorage is Traversable, so you can foreach over it as well.

On a sidenote, PHP also has native interfaces for Subject and Observer.

Gordon
+1 that's the best approach. Not to mention that as of PHP 5.3, `SplObjectStorage` implements `ArrayAccess`.
Ionuț G. Stan
I would suggest to use `if(($key = array_search($value, $array, $strict)) !== false)` cuz `0 == false`
Anpher
@Anpher good call. Fixed. Though I really think the OP should use SplObjectStorage if there is only objects to handle.
Gordon
+1  A: 

I agree with the answers above, but for the sake of completeness (where you may not have unique IDs to use as a key) my preferred methods of removing values from an array are as follows:

/**
 * Remove each instance of a value within an array
 * @param array $array
 * @param mixed $value
 * @return array
 */
function array_remove(&$array, $value)
{
    return array_filter($array, function($a) use($value) {
        return $a !== $value;
    });
}

/**
 * Remove each instance of an object within an array (matched on a given property, $prop)
 * @param array $array
 * @param mixed $value
 * @param string $prop
 * @return array
 */
function array_remove_object(&$array, $value, $prop)
{
    return array_filter($array, function($a) use($value, $prop) {
        return $a->$prop !== $value;
    });
}

Which are used in the following way:

$values = array(
    1, 2, 5, 3, 5, 6, 7, 1, 2, 4, 5, 6, 6, 8, 8,
);
print_r(array_remove($values, 6));

class Obj {
    public $id;
    public function __construct($id) {
        $this->id = $id;
    }
}
$objects = array(
    new Obj(1), new Obj(2), new Obj(4), new Obj(3), new Obj(6), new Obj(4), new Obj(3), new Obj(1), new Obj(5),
);
print_r(array_remove_object($objects, 1, 'id'));

Hope that helps.

icio
A: 

I believe this is the best way

$index = array_search($o,$this->arrObservers,true); unset($this->arrObservers[$index]);

A: 

Try this, will solve your problem.
class Data{

private $arrObservers;

public add(Observer $o) {
array_push($this->arrObservers,$o);
}
public remove($Observer $o) {
unset($this->arrObservers[$o]);
}

}

Vaibhav Malushte
array_push will assign a numeric key, so you wouldnt find $o as key, even if arrays could use objects for keys
Gordon