I was recently working on a project and found that I had to merge two very complex objects using PHP. I went to search for a solution and of course found array_merge()
and array_merge_recursively()
. So naturally, I thought I would start out by converting my objects into arrays and using array_merge_recursively. For which I achieved the following results:
class Utils {
/**
* Recursively merges two objects and returns a resulting object.
* @param object $obj1 The base object
* @param object $obj2 The merge object
* @return object The merged object
*/
public function mergeObjectsRecursively($obj1, $obj2)
{
$baseObject = (array) $obj1;
$mergeObject = (array) $obj2;
$merged = array_merge_recursive($baseObject, $mergeObject);
return (object) $merged;
}
}
$utils = new Utils();
$obj1 = (object) [
'debug' => true,
'routes' => (object) [
'test' => '/my-tests'
]
];
$obj2 = (object) [
'routes' => (object) [
'test' => '/my-tests-replaced'
]
];
$obj3 = $utils->mergeObjectsRecursively($obj1, $obj2);
var_dump($obj3);
/**
* Resulting Object:
* object(stdClass)#6 (2) {
* ["debug"]=>
* bool(true)
* ["routes"]=>
* array(1) {
* ["test"]=>
* array(2) {
* [0]=>
* string(9) "/my-tests"
* [1]=>
* string(18) "/my-tests-replaced"
* }
* }
* }
*/
Notice that in the approach above, the resulting object is an object with a “routes” property that was converted from an object into an array. And not only that, but the obj->routes->test
values have been combined into an array of values.
Not Acceptable!
THE ANSWER: Recursively Merge Two PHP Objects
The approach we need to take is to create our own merging logic so that it will override values instead of combining them. Here is the new approach:
class Utils {
/**
* Recursively merges two objects and returns a resulting object.
* @param object $obj1 The base object
* @param object $obj2 The merge object
* @return object The merged object
*/
public function mergeObjectsRecursively($obj1, $obj2)
{
$merged = $this->_mergeRecursively($obj1, $obj2);
return $merged;
}
/**
* Recursively merges two objects and returns a resulting object.
* @param object $obj1 The base object
* @param object $obj2 The merge object
* @return object The merged object
*/
private function _mergeRecursively($obj1, $obj2) {
if (is_object($obj2)) {
$keys = array_keys(get_object_vars($obj2));
foreach ($keys as $key) {
if (
isset($obj1->{$key})
&& is_object($obj1->{$key})
&& is_object($obj2->{$key})
) {
$obj1->{$key} = $this->_mergeRecursively($obj1->{$key}, $obj2->{$key});
} elseif (isset($obj1->{$key})
&& is_array($obj1->{$key})
&& is_array($obj2->{$key})) {
$obj1->{$key} = $this->_mergeRecursively($obj1->{$key}, $obj2->{$key});
} else {
$obj1->{$key} = $obj2->{$key};
}
}
} elseif (is_array($obj2)) {
if (
is_array($obj1)
&& is_array($obj2)
) {
$obj1 = array_merge_recursive($obj1, $obj2);
} else {
$obj1 = $obj2;
}
}
return $obj1;
}
}
$utils = new Utils();
$obj1 = (object) [
'debug' => true,
'modules' => [
'Module1'
],
'routes' => (object) [
'test' => '/my-tests',
'override' => 'false',
'test2' => (object) [
'override' => 'false',
'shouldStay' => 'true'
]
]
];
$obj2 = (object) [
'debug' => false,
'modules' => [
'Module2',
'Module3'
],
'routes' => (object) [
'route1' => (object) [
'path' => '/'
],
'override' => 'true',
'test2' => (object) [
'override' => 'true'
]
]
];
$obj3 = $utils->mergeObjectsRecursively($obj1, $obj2);
var_dump($obj3);
/**
* Resulting Object:
* object(stdClass)#4 (3) {
* ["debug"]=>
* bool(false)
* ["modules"]=>
* array(3) {
* [0]=>
* string(7) "Module1"
* [1]=>
* string(7) "Module2"
* [2]=>
* string(7) "Module3"
* }
* ["routes"]=>
* object(stdClass)#3 (4) {
* ["test"]=>
* string(9) "/my-tests"
* ["override"]=>
* string(4) "true"
* ["test2"]=>
* object(stdClass)#2 (2) {
* ["override"]=>
* string(4) "true"
* ["shouldStay"]=>
* string(4) "true"
* }
* ["route1"]=>
* object(stdClass)#5 (1) {
* ["path"]=>
* string(1) "/"
* }
* }
* }
* /
Notice that the resulting object remains in tact. $obj->routes->test
contains the replaced value and both $obj->routes
and $obj->routes->test
remain an objects.
Enjoy!
The post Tutorial: How to Recursively Merge Two Objects In PHP appeared first on UA1 Labs.
Top comments (0)