Search code examples
phpobjectclone

PHP: how to "clone from" another object of same class? 'Internally clone' current object from source obj, NOT clone another object from current


In my current application I have a number of objects that are required repeatedly

To save overhead of instantiating the same object over and over again, I keep an array of 'known' objects.
I can check the input data against the array, and - if already set - use the existing object, else go ahead to instantiate the new object and add the pointer reference to the relevant known objects array.

In most use cases, I can check prior to instantiating the class:

if(array_key_exists($identifier,$known_ClassObjects)){
   $object = $known_ClassObjects[$identifier];
} else {
   $object = new Class($params);
}

However, in some cases I can only identify that the object I am instantiating already exists once already inside it.

In that case I would like to be able to do one of 2 things:

  1. return the OTHER (pre-existing) object instead of this one, e.g.
class Test{

    public function __construct($params){
        
        //apply processing to $params, resulting in $identifier 

        if(array_key_exists($identifier, $known_ClassObjects)){ //$known_ClassObjects is global

             return $known_ClassObjects[$identifier];

        } else {

             //continue __construct() logic

             return $this;
        }

    }
}

However, PHP ALWAYS returns the current object, even with code return $other_object;

  1. 'Internally Clone' the current object from the found one [of the same class, obv] so that when it returns, it has the correct relevant properties populated.

NOTE: including any parent/child class properties -> I want to make this object EXACTLY the same as the found one.

So, if there was a PHP function clone_from(), it would work something like:

if(array_key_exists($identifier,$known_ClassObjects)){
   $this->clone_from ($known_ClassObjects[$identifier]);

} else {
   //continue with __construct()

}
return $this;

Given that 1. doesn't work and 2. doesn't seem to exist, I have only been able to do this in very 'hacky' ways: iterating through all properties of source object and setting all properties of current object.

However, this has obvious issues esp. with extended parent/child classes etc. which then requires things like reflection classes.

This seems like there SHOULD be a really simple solution, but I have been unable to find one


Solution

  • What you actually could do is using either a Singleton Pattern or a Factory pattern - in both cases, the creation of objects is controlled by some piece of code and you can decide, which object to return. Singleton already is a special form of a Factory pattern.

    Consider this code

    class Singleton {
        protected static $instance; 
        
        protected function __construct() { 
        }
        
        public static function instance() {
            if (self::$instance === null) {
                self::$instance = new self();
            }
            return self::$instance;
        }
    } 
    

    The constructor is protected which will prevent a object construction from "outside" via new. However, there is also a static function instance with which somebody can request an object instance from the factory method.

    $obj = Singleton::instance(); 
    

    So, the (internal) object is created only once, and then delivered afterwards until the script ends.