Implementing Singleton
Singleton is even simpler than Abstract Factory; it's an elegant
idea but there isn't a lot of variation in it. Here's how the
Horde Registry:: class implements it:
<?php /** * Returns a reference to the global Registry object, only * creating it if it doesn't already exist. * * This method must be invoked as: $registry = &Registry::singleton() * * @return object The Horde Registry instance. */ function &singleton() { static $registry;
if (!isset($registry)) { $registry = new Registry(); }
return $registry; }
Note where we use "&" in the name of the function. It must be
written that way to tell the PHP engine that the function should
return a reference.
Those of you familiar with this pattern in other languages will be
wondering about something: no, we can't make the constructor
private in PHP. In most languages, you would declare the
constructor of a singleton class private, so that nothing outside
of the class could instantiate the class - only the singleton()
accessor. In PHP we don't have that enforcement, so you simply
have to be consistent about always using the singleton() method
and never calling new.
Here's a slightly more complicated example, again from Horde's
Auth library. This has two wrinkles in it: it calls a factory()
method, instead of calling new directly, and it also modifies the
pattern slightly to only create one instance of an Auth object per
set of parameters. This means that it will give you back different
objects when you ask for a SQL authentication object and a
Kerberos authentication object, but if you ask for a SQL
authentication object again, it'll give you back the same one you
got the first time.
<?php /** * Attempts to return a reference to a concrete Auth instance * based on $driver. It will only create a new instance if no Auth * instance with the same parameters currently exists. * * This should be used if multiple authentication sources (and, * thus, multiple Auth instances) are required. * * This method must be invoked as: $var = &Auth::singleton() * * @access public * * @param string $driver The type of concrete Auth subclass to * return. This is based on the storage * driver ($driver). The code is dynamically * included. * @param optional array $params A hash containing any additional * configuration or connection parameters a * subclass might need. * * @return object Auth The concrete Auth reference, or false on an error. */ function &singleton($driver, $params = null) { static $instances;
if (!isset($instances)) { $instances = array(); }
if (is_null($params)) { $params = Horde::getDriverConfig('auth', $driver); }
if (is_array($driver)) { $drivertag = implode(':', $driver); } else { $drivertag = $driver; } $signature = md5(strtolower($drivertag) . '][' . @implode('][', $params)); if (!array_key_exists($signature, $instances)) { $instances[$signature] = &Auth::factory($driver, $params); }
return $instances[$signature]; }
|