Re: OO and "Singleton" class

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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



[Index of Archives]     [PHP Home]     [Apache Users]     [PHP on Windows]     [Kernel Newbies]     [PHP Install]     [PHP Classes]     [Pear]     [Postgresql]     [Postgresql PHP]     [PHP on Windows]     [PHP Database Programming]     [PHP SOAP]

  Powered by Linux