Singleton
From Wikipedia
In software engineering, the singleton pattern is a design pattern that is used to restrict instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system. Sometimes it is generalized to systems that operate more efficiently when only one or a few objects exist. It is also considered an anti-pattern by some people, who feel that it is often used as a euphemism for global variable
Basically, the last point is true.
Whatever we think about Singleton, we cannot say that we do not use this pattern to have the same instance, or object, in every place of our application.
The most common case scenario, is usually a database object, or a global queue, used as a stack, or something similar, like a template engine instance or a DOM / XML node.
The worst thing ever, is that with languages like PHP and JavaScript, the Singleton pattern is really hard to implement correctly.
Why bother with a class?
In a lot of frameworks, as in a lot of libraries, I have seen every kind of Singleton implementation, and most of them, are conceptually hilarious.
// PHP Singleton classic example
Singleton::load('MyCLassName');
MyClassName::getInstance();
// JavaSript classic example
MyConstructor.getInstance();
// where in different cases, getInstance
// is not even defined inside a closure
// to preserve singleton integrity ...
// ... but does exist a way to make
// a JS constructor private? NO
With PHP, problems are different:
- if there's no magic __clone method, it does not make sense
- if you serialize and unserialize objects, it could not make sense
- if you create a Singleton class, it is nearly impossible to extend correctly its behaviour (come on lazy binds and PHP 5.3!!!)
- if you try to create a __callStatic method, you simply have to wait next PHP release
In PHP again, as is for JavaScript, outside a closure, every static function is global.
This means that we do not need to use global something, in PHP, and we do not use, usually, window as prefix to use declared function.
It is true, the most horrible piece of code you can spot in an entire PHP application, is the usage of global keyword to transport variables everywhere.
We do not need that, and we can have a Singleton behaviour, simply using a function !!!
function Singleton($__CLASS__){
// webreflection.blogspot.com
static $list = array();
if(!isset($list[$__CLASS__])){
$arguments = func_get_args();
array_shift($arguments);
$instance = new ReflectionClass($__CLASS__);
$list[$__CLASS__] = $instance->getConstructor() ? $instance->newInstanceArgs($arguments) : $instance->newInstance();
}
return $list[$__CLASS__];
}
Is static variable private inside function scope? Yes
Is this function smarter than a public static method? Yes
class A {
protected $value = '123';
function write($what){
echo $what.$this->value;
return $this;
}
}
class B extends A {
function __construct($value){
$this->value = $value;
}
}
echo '', var_dump(Singleton('A') === Singleton('A')), '';
echo '', var_dump(';
Singleton('B', 'my value')->write('Hello World') === Singleton('B')
), '
// true, Hello Worldmy value, true
Do you really want a class?
Ok, somebody could thing that above function is pointless, so here there is a class that will use the same function.
class Singleton {
// webreflection.blogspot.com
private $_class,
$_instance;
public function __construct($__CLASS__){
$arguments = func_get_args();
$this->_class = new ReflectionClass($this->_instance = call_user_func_array('Singleton', $arguments));
}
public function __get($property){
return $this->_instance->$property;
}
public function __call($method, array $arguments){
return $this->_class->getMethod($method)->invokeArgs($this->_instance, $arguments);
}
public function __set($property, $value){
$this->_instance->$property = $value;
}
public function equal($_instance){
return $_instance instanceof Singleton ? $this->_instance === $_instance->_instance : $this->_instance === $_instance;
}
}
With above class, using the Singleton function as well, you can even use the new keyword to obtain every time the same instance.
$b = new Singleton('B', 'my value');
echo '', var_dump(';
$b->equal(Singleton('B')->write('Hello World')) &&
$b->equal(new Singleton('B'))
), '
Well, at this point we have the shortest way to obtain the same behaviour, using, or not, a class.
Factory
From Wikipedia
The Factory pattern is a creational design pattern used in software development to encapsulate the processes involved in the creation of objects.
The creation of an object often requires complex processes not appropriate to include within a composing object. The object's creation may lead to a significant duplication of code, may require information not accessible to the composing object, may not provide a sufficient level of abstraction, or may otherwise not be part of the composing object's concerns.
Specially in PHP, a Factory pattern is useful to avoid problems with new keyword when you create an object.
For example, this is not possible:
new Class("stuff")->doStuff();
With a Factory behaviour it is natural to do something like this:
Factory('Class')->doStuff();
In those case when we need an instance once, or few times, and never more, to do some super cool computation, we could avoid variable assignment and, in some case, use a function with the same class name as proposed few days ago.
But this time, using exactly the same concept of Singleton, it is even more simple to create a general purpose Factory function:
function Factory($__CLASS__){
// webreflection.blogspot.com
static $list = array();
if(!isset($list[$__CLASS__]))
$list[$__CLASS__] = new ReflectionClass($__CLASS__);
$arguments = func_get_args();
array_shift($arguments);
return $list[$__CLASS__]->getConstructor() ? $list[$__CLASS__]->newInstanceArgs($arguments) : $list[$__CLASS__]->newInstance();
}
Some example?
class A {
public function setName($name){
$this->name = $name;
return $this;
}
}
$me = Factory('A')->setName('Andrea');
echo $me->name; // Andrea
Not every consideration I did for Singleton pattern is true for Factory one, but the structure of the function, as the possible class, is about the same.
At this point, assuming that in my implementation Factory is an extended version of the Singleton, creating more instances than one, you can have a look into the complete source of my Factory and Singleton implementation.
Why there is JavaScript in this post topic?
The reaon is simple, everything I have done with PHP, is simply replicable with JavaScript, but this time, with only 8 lines of code:
// webreflection.blogspot.com
Factory = function(__CLASS__){
for(var i = 1, length = arguments.length, args = new Array(length - 1); i < length; i++)
args[i - 1] = "arguments[" + i + "]";
return Function("return new " + __CLASS__ + "(" + args.join(",") + ")").apply(null, arguments);
};
Singleton = function(list){return function(__CLASS__){
return __CLASS__ in list ? list[__CLASS__] : list[__CLASS__] = Factory.apply(null, arguments);
}}({});
Seems to be simple, isn't it? :geek:
Good thinking, thanks for sharing.
ReplyDeleteOO rewriting a lot of code, searching for the best possible way...