On Tue, Sep 1, 2009 at 5:16 PM, Paul M Foster<pa...@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.

--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to