Re: OO and "Singleton" class

From: Date: Tue, 01 Sep 2009 22:06:24 +0000
Subject: Re: OO and "Singleton" class
References: 1  Groups: php.general 
Request: Send a blank email to php-general+get-297586@lists.php.net to get a copy of this message
On Tue, Sep 1, 2009 at 5:16 PM, Paul M Foster<paulf@quillandmouse.com> wrote: > > I'm a little fuzzy on some of the PHP implementation details for some > stuff. In PHP (5 <= phpversion() < 5.3), I'd like a configuration class > which can only effectively be instantiated once. Will the following code > do this? Any other suggestions or corrections? (Code is untested. Feel > free to complain about syntax.) > > class config > { >    private static $cfg; > >    // Initializes the configuration from main config file >    function __construct() >    { >        if (!is_array(self::$cfg)) { >            if (defined('CFGFILE')) { >                include(CFGFILE); >                self::$cfg = $config; >            } >            else >                self::$cfg = array(); >        } >    } > >    // Returns a config item or null if not found >    function item($index) >    { >        if (array_key_exists($index, self::$cfg)) >            return self::$cfg[$index]; >        else >            return null; >    } > >    // Sets a config item, optionally overwriting. >    // Returns true on success, false on failure. >    function set($index, $value, $overwrite = true) >    { >        $write = false; >        if (array_key_exists($index, self::$cfg) and $overwrite) >            $write = true; >        elseif (!array_key_exists($index, self::$cfg)) >            $write = true; >        if ($write) { >            self::$cfg[$index] = $value; >            return true; >        } >        else >            return false; >    } > > }; > > Paul > > -- > Paul M. Foster > > -- > PHP General Mailing List (http://www.php.net/) > To unsubscribe, visit: http://www.php.net/unsub.php > > The primary thing you need to do to make a class a singleton is disallow the instantiation of a class directly. Which means using visibility, which is conspicuously absent from your example above. So, to prevent normal instantiation, we make the constructor private. Also, we need a method to retrieve the instance. Static members serve this purpose: class Singleton { private static $instance; private function __construct() { } public static function getInstance() { if( ! self::$instance instanceof Singleton) //replace Singleton with class name self::$instance = new Singleton; //replace Singleton with class name return self::$instance; } public function __clone() { throw new Exception('Cannot clone a Singleton'); } } This class "shell" will prevent people from instantiating it ($foo = new Singleton is an error). Instead, deployment will look like `$foo = Singleton::getInstance()` which, as you can tell, always returns the same instance. Throwing an exception out of __clone() will prevent something like $foo = Singleton::getInstance(); $bar = clone $foo; which is something I see overlooked a lot. So, if you wanted to convert your full class to a singleton it would look something like: class config { private static $instance; private static $cfg; private function __construct() { if(!is_array(self::$cfg)) { if(defined('CFGFILE')) { include(CFGFILE); self::$cfg = $config; } else { self::$cfg = array(); } } } public function getInstance() { if(!(self::$instance instanceof config)) { self::$instance = new config(); } return self::$instance; } public function __clone() { throw new Exception("Cannot clone a Singleton."); } public function item($index) { if(array_key_exists($index, self::$cfg)) return self::$cfg[$index]; else return null; } // Sets a config item, optionally overwriting. // Returns true on success, false on failure. function set($index, $value, $overwrite = true) { $write = false; if (array_key_exists($index, self::$cfg) and $overwrite) { $write = true; } elseif (!array_key_exists($index, self::$cfg)) { $write = true; } if ($write) { self::$cfg[$index] = $value; return true; } else { return false; } } } Note that this is also completely untested or anything of the sort.

« previous php.general (#297586) next »