Categories
Articles

Php5 Simple Singleton Design Pattern

I wanted to reproduce a simple singleton design pattern in PHP 5. After reviewing many overly complex examples, I synthesized to this example.

It also makes use of the PHP5 magic function __get and __set also poorly addressed in web postings. Going for cleaner code I like to see $obj->prop rather than $obj->getProp() and $obj->setProp(value) in the code. But I am greedy and want to have read only and write only props. So I configured the various examples to achieve that goal. As well you can see in the __set and __get methods you may choose to work the props or call a private method that would handle the validation and proper handling of the set and return values. I demonstrated this here.

This is the singleton running with the idea of a single configuration object for an application. It only has one real property named isDebugging for the example.

<?php
class Config
	static private $_instance;
    private $isDebugging = false; // Read write
	private $version = "1.1"   ;  // Read only
	private $cannotReadProp = "x" ;
	public static function getInstance($args = array())
	{
		if(!self::$_instance)
		{
			self::$_instance = new Config();
		}
		self::$_instance->setIsDebugging(isset($args['isDebugging']) ? $args['isDebugging'] : self::$_instance->isDebugging);
		return self::$_instance;
	}
	private static function setIsDebugging($value)
	{
		self::$_instance->isDebugging = is_bool($value)? $value: self::$_instance->isDebugging;
	}
	public static function __set($prop, $value)

		if (isset(self::$_instance->$prop)
		{
			switch ($prop)
			{
				case 'isDebugging':
					self::$_instance->setIsDebugging($value);
					break
				default :
					throw new Exception('Cannot write property [' . $prop . ']',1);
			}
		}
		else
		{
			throw new Exception('Undefined property [' . $prop . ']',1);
		}
	}
	public static function __get($prop)
	{
		if (isset(self::$_instance->$prop))
		{
			switch ($prop)
			{
				case 'isDebugging':
					return self::$_instance->isDebugging
					break;
			       default :
					throw new Exception('Cannot read property [' . $prop . ']',1);
			}
		}
		else
		{
			throw new Exception('Undefined property [' . $prop . ']',1);
		}
	}
}
?>

This is a testing script for the above. Note there are some commented lines for testing the exception thowing.

<?php
	include 'config.inc.php';
	// First reference
	$myConfig1 = Config::getInstance();
	// Get property
	echo ('$myConfig1->isDebugging:' . ($myConfig1->isDebugging ? "true" : "false")) . '<br/>';
	// Set property
	echo 'Set $myConfig1->isDebugging = true <br/>';
	$myConfig1->isDebugging = true;
	echo ('$myConfig1->isDebugging:' . ($myConfig1->isDebugging ? "true" : "false")) . '<br/>';
	// Second reference
	echo '<br/>';
	echo 'Add second reference and not getInstance args<br/>';
	echo '$myConfig2 = Config::getInstance(); <br/>';
	$myConfig2 = Config::getInstance();
	echo ('$myConfig1->isDebugging:' . ($myConfig1->isDebugging ? "true" : "false")) . '<br/>';
	echo ('$myConfig2->isDebugging:' . ($myConfig2->isDebugging ? "true" : "false")) . '<br/>';
	// Third reference<br />
	echo '<br/>';
	echo 'Add third reference and change prop via getInstance arg <br/>';
	echo '$myConfig3 = Config::getInstance(array(\'isDebugging\'=>false)); <br/>';
	$myConfig3 = Config::getInstance(array('isDebugging'=>false));
	echo ('$myConfig1->isDebugging:' . ($myConfig1->isDebugging ? "true" : "false")) . '<br/>';
	echo ('$myConfig2->isDebugging:' . ($myConfig2->isDebugging ? "true" : "false")) . '<br/>';
	echo ('$myConfig3->isDebugging:' . ($myConfig3->isDebugging ? "true" : "false")) . '<br/>';
	// Set property via second instance
	echo '<br/>';
	echo 'Set property via second instance <br/>';
	echo 'Set $myConfig2->isDebugging = true <br/>';
	$myConfig2->isDebugging = true;
	echo ('$myConfig1->isDebugging:' . ($myConfig1->isDebugging ? "true" : "false")) . '<br/>';
	echo ('$myConfig2->isDebugging:' . ($myConfig2->isDebugging ? "true" : "false")) . '<br/>';
	echo ('$myConfig3->isDebugging:' . ($myConfig3->isDebugging ? "true" : "false")) . '<br/>';
	// Set property to incorrect data type
	echo '<br/>';
	echo 'Set $myConfig1->isDebugging = 123<br/>';
	echo 'No exception for invalid data type and not prop change.<br/>';
	$myConfig1->isDebugging = 123;
	echo ('$myConfig1->isDebugging:' . ($myConfig1->isDebugging ? "true" : "false")) . '<br/>';
	echo ('$myConfig2->isDebugging:' . ($myConfig2->isDebugging ? "true" : "false")) . '<br/>';
	echo ('$myConfig3->isDebugging:' . ($myConfig3->isDebugging ? "true" : "false")) . '<br/>';
	// Setter throws undefined property exception
	//$myConfig1->test = true;
	// Getter throws undefined property exception
	//echo '$myConfig1->test:' . $myConfig1->test . '<br/>';
	// Setter throws cannot write property exception
	//$myConfig1->version = '2.2';
	// Setter throws cannot read property exception
	//echo '$myConfig1->cannotReadProp:' . $myConfig1->cannotReadProp . '<br/>';
?>