Search code examples
phpreferencerestore

PHP: How to restore the overriden by reference object


I want to make a function, modify for instance, for clients where user can modify passed object BUT not override it with another one.

I mean... if any user wants to override the passed object for instance: $originObject = new \StdClass(); after the function execution I'll be able to restore the SAME object passed to the function.

function modify(object &$obj): void {
    $obj = new \StdClass();
}

function back(object &$obj, int $previousObjectId, string $serializedOriginObject): void {
    if (\spl_object_id($obj) !== $previousObjectId) {
        $obj = \unserialize($serializedOriginObject);
    }
}

$originObject = new \StdClass; // ORIGIN OBJECT
$serializedOriginObject = \serialize($originObject);

$objectIdBeforeModify = \spl_object_id($originObject);
\var_dump($objectIdBeforeModify); // in my case object id: "1"

modify($originObject); // PASSES BY REFERENCE AND OVERRIDES IT
$objectIdAfterModify = \spl_object_id($originObject);
\var_dump($objectIdAfterModify); // in my case object id: "2"

back($originObject, $objectIdBeforeModify, $serializedOriginObject);
$returnedObjectId = \spl_object_id($originObject);
\var_dump($returnedObjectId);    // in my case object id: "1"

My question is: are there any ways to make it without serialization? To restore an object that was overriden, cuz it was passed by reference in the function.


Solution

  • Just assign the object to another variable, using a normal "by value" assignment (no &). The fact that $obj was passed by reference won't be relevant, the current value will be used.

    For instance, using a class just to have somewhere to store the value:

    class Whatever {
        private $backup;
    
        public function replace(object &$obj) {
            $this->backup = $obj;
            $obj = new stdClass;
        }
    
        public function restore(object &$obj) {
            $obj = $this->backup; 
        }
    }
    

    Note that because $obj is an object, it is also mutable even when assigned by value. That is, code elsewhere could do something like $obj->foo = 42; and that would change $backup, because it is the same object being referenced.

    If you don't want that, you could store a clone instead.