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