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/>'; ?>