Мне интересно, можно ли использовать ключевое слово 'new' для возврата ссылки на существующий объект вместо нового объекта. А если нет, то какой был бы лучший способ избежать сосуществования объектов с одинаковыми параметрами?
У меня есть класс с аргументами в конструкторе. Если я использую аргументы, аналогичные аргументам существующего экземпляра, я бы хотел, чтобы мой новый объект был ссылкой на существующий. Является ли это возможным? Я понимаю, что он отличается от синглтона, так как в этом случае мы можем иметь несколько экземпляров одного и того же класса, но не несколько экземпляров, использующих одни и те же параметры.
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
Сначала несколько фактов:
Вывод:
* Существует небольшое различие между ними, и это связано с использованием делегирования $ a! = $ B, но с использованием заводских методов $ a === $ b (см. Ниже)
Пример делегирования:
// 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);
Пример фабричного класса:
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);
Не проще ли было бы прямо хранить ссылки на объекты в ваших instances
var?
if (!isset(self::$instances[$myparam])) { self::$instances[$myParam] = ... new object here ...; } else return &self::$instances[$myParam]; }
Просто гадать, но похоже, что сохранение вашего простого целочисленного параметра в виде ключа массива к кешу экземпляров было бы «дешевле», чем хранение сигнатуры sha1 сериализованной структуры, которая потенциально могла бы НЕ быть одинаковой, даже если объект имеет тот же начальный параметр ,