Tutorial: How to Recursively Merge Two Objects In PHP
Tags: tutorials
Published: 2018-06-11 09:13:11

---
title: Tutorial: How to Recursively Merge Two Objects In PHP
published: true
tags: Tutorials
canonical_url: https://ua1.us/news/tutorials/tutorial-how-to-recursively-merge-two-objects-in-php/
---

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](https://ua1.us/news/tutorials/tutorial-how-to-recursively-merge-two-objects-in-php/) appeared first on [UA1 Labs](https://ua1.us).