PHP Getting a reference through a constructor?

2019-03-02 04:33发布

问题:

I am wondering if it is possible while using the keyword 'new' to return a reference to an existing object instead of a new object. And if not, what would be the best way to avoid co-existence of objects with the same parameters?

I have a class with arguments on the constructor. If I am using arguments similar to the ones of an existing instance, I'd like my new object to be a reference to the existing one. Is it possible? I understand it is different than a singleton as in this case we can have several instances of the same class, but not several instances using the same parameters.

class myClass{
 public $signature; /* Unique signature for the connection */
 public static $instances = array(); /* Array of references to connection */
 private static function singleton($cfg,$inst){
   $signature = sha1(serialize($cfg));
   foreach ( self::$instances as $obj )
   {
     if ( $obj->signature == $signature )
       return $obj;
   }
   array_push(self::$instances,$inst);
   return true;
 }
 function __construct($myParam){
   if ( is_object(self::singleton($myParam,$this) )
     // Here I'd like $this to become the ref of my existing object
   else
   {
     $this->signature = $myParam;
     // I construct my new object
   }
 }
}
$e1 = new myClass(1);
$e2 = new myClass(2);
$e3 = new myClass(1); // $e3 should be a reference to $e1

回答1:

First a few facts:

  • The constructor can never return a value.
  • $this cannot be reassigned (it could in PHP 4 but wasn't intended, and was undocumented)

Conclusion:

  • Use factory methods or delegation.*

* There is a slight difference between the two, and that is that using delegation $a!=$b, but using factory methods $a === $b (see below)

Delegation example:

// Declare the delegate that will be wrapped by DelegationClass
// * Only public methods/properties will be accessible
class MyClass {
    public $a;
    public function a($a) {
        echo "This is a(\$a=$a)\n";
    }
}

class MyDelegationClass {
    static protected $_delegation = 'MyClass'; // define the delegate
    static protected $_i = array(); // instances
    protected $_l = null; // delegation link
    public function __construct($n) {
       if (!array_key_exists($n,self::$_i)) {
           // ensures that the instance is always created
           self::$_i[$n] = new self::$_delegation; 
        }
        $this->_l = self::$_i[$n]; // link to delegate
    }
    public function __get($v) {
        return $this->_l->$v; // get property from delegate link
    }
    public function __set($k,$v) {
        return $this->_l->$k = $v; // set property on delegate link
    }
    public function __call($f,$p) {
        // call method on delegate link
        return call_user_func_array(array($this->_l,$f),$p); 
    }
}
// $a != $b, but $a->a === $b->a
$a = new MyDelegationClass(1);
$b = new MyDelegationClass(1);

Factory class example:

class MyFactoryClass {
    static protected $_i = array(); // instances
    public static function newMyClass($n) {
       if (!array_key_exists($n,self::$_i)) {
           // ensures that the instance is always created
           self::$_i[$n] = new MyClass; 
        }
        return self::$_i[$n]; // return instance
    }
}
// $a === $b
$a = MyFactoryClass::newMyClass(1);
$b = MyFactoryClass::newMyClass(1);


回答2:

Wouldn't it just be easier to directly store the object references in your instances var?

if (!isset(self::$instances[$myparam])) {
    self::$instances[$myParam] = ... new object here ...;
} else
    return &self::$instances[$myParam];
}

Just guessing, but it seems that storing your simple integer parameter as an array key to the instances cache would be "cheaper" than storing an sha1 signature of a serialized structure that could potentially NOT be the same even if the object has the same initial parameter.



标签: php oop