We have two PHP5 objects and would like to merge the content of one into the second. There are no notion of subclasses between them so the solutions described in the following topic cannot apply.
Remarks:
- Remember these are objects, not classes.
- Objects will contain quite a lot of fields so a ``foreach`` would be quite slow.
- So far we consider transforming objects A and B into arrays then merging them using array_merge() before re-transforming into an object but we can't say we are proud if this.
If your objects only contain fields (no methods), this works:
$obj_merged = (object) array_merge((array) $obj1, (array) $obj2);
This actually also works when objects have methods. (tested with PHP 5.3 and 5.6)
Another Way:
foreach($objectA as $k => $v) $objectB->$k = $v;
- Specify reference or clone
- Specify first or last entry to take precedence
- Multiple (more than two) object merging with syntax similarity to array_merge
- Method linking: $obj->f1()->f2()->f3()...
- Dynamic composites: $obj->merge(...) /* work here */ $obj->merge(...)
class Compositor { protected $composite = array(); protected $use_reference; protected $first_precedence; /** * __construct, Constructor * * Used to set options. * * @param bool $use_reference whether to use a reference (TRUE) or to copy the object (FALSE) [default] * @param bool $first_precedence whether the first entry takes precedence (TRUE) or last entry takes precedence (FALSE) [default] */ public function __construct($use_reference = FALSE, $first_precedence = FALSE) { // Use a reference $this->use_reference = $use_reference === TRUE ? TRUE : FALSE; $this->first_precedence = $first_precedence === TRUE ? TRUE : FALSE; } /** * Merge, used to merge multiple objects stored in an array * * This is used to *start* the merge or to merge an array of objects. * It is not needed to start the merge, but visually is nice. * * @param object[]|object $objects array of objects to merge or a single object * @return object the instance to enable linking */ public function & merge() { $objects = func_get_args(); // Each object foreach($objects as &$object) $this->with($object); // Garbage collection unset($object); // Return $this instance return $this; } /** * With, used to merge a singluar object * * Used to add an object to the composition * * @param object $object an object to merge * @return object the instance to enable linking */ public function & with(&$object) { // An object if(is_object($object)) { // Reference if($this->use_reference) { if($this->first_precedence) array_push($this->composite, $object); else array_unshift($this->composite, $object); } // Clone else { if($this->first_precedence) array_push($this->composite, clone $object); else array_unshift($this->composite, clone $object); } } // Return $this instance return $this; } /** * __get, retrieves the psudo merged object * * @param string $name name of the variable in the object * @return mixed returns a reference to the requested variable * */ public function & __get($name) { $return = NULL; foreach($this->composite as &$object) { if(isset($object->$name)) { $return =& $object->$name; break; } } // Garbage collection unset($object); return $return; } }
Usage:
$obj = new Compositor(use_reference, first_precedence); $obj->merge([object $object [, object $object [, object $...]]]); $obj->with([object $object]);
Example:
$obj1 = new stdClass(); $obj1->a = 'obj1:a'; $obj1->b = 'obj1:b'; $obj1->c = 'obj1:c'; $obj2 = new stdClass(); $obj2->a = 'obj2:a'; $obj2->b = 'obj2:b'; $obj2->d = 'obj2:d'; $obj3 = new Compositor(); $obj3->merge($obj1, $obj2); $obj1->c = '#obj1:c'; var_dump($obj3->a, $obj3->b, $obj3->c, $obj3->d); // obj2:a, obj2:b, obj1:c, obj2:d $obj1->c; $obj3 = new Compositor(TRUE); $obj3->merge($obj1)->with($obj2); $obj1->c = '#obj1:c'; var_dump($obj3->a, $obj3->b, $obj3->c, $obj3->d); // obj1:a, obj1:b, obj1:c, obj2:d $obj1->c = 'obj1:c'; $obj3 = new Compositor(FALSE, TRUE); $obj3->with($obj1)->with($obj2); $obj1->c = '#obj1:c'; var_dump($obj3->a, $obj3->b, $obj3->c, $obj3->d); // obj1:a, obj1:b, #obj1:c, obj2:d $obj1->c = 'obj1:c';
The best method to merge PHP objects
By Game Changer →
Wednesday, December 9, 2015