Php

Php5 Singleton pattern with magic __get and __set

March 30th, 2008 at 11:41am Under General stuff+ Php+ Php 5

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.

  1. <?php
  2.  
  3. class Config {
  4.    static private $_instance;
  5.     private $isDebugging = false; // Read write
  6.    private $version = "1.1"   ;  // Read only
  7.    private $cannotReadProp = "x" ;
  8.    public static function getInstance($args = array())
  9.    {
  10.       if(!self::$_instance)
  11.       {
  12.          self::$_instance = new Config();
  13.          
  14.       }
  15.       self::$_instance->setIsDebugging(isset($args['isDebugging']) ? $args['isDebugging'] : self::$_instance->isDebugging);
  16.       return self::$_instance;
  17.    }
  18.  
  19.    private static function setIsDebugging($value)
  20.    {
  21.       self::$_instance->isDebugging = is_bool($value)? $value: self::$_instance->isDebugging;
  22.    
  23.    }
  24.    
  25.    public static function __set($prop, $value)
  26.    {
  27.       if (isset(self::$_instance->$prop))
  28.       {
  29.          switch ($prop)
  30.          {
  31.             case 'isDebugging':
  32.                self::$_instance->setIsDebugging($value);
  33.                break;
  34.  
  35.             default :
  36.                throw new Exception('Cannot write property [' . $prop . ']',1);
  37.          }
  38.  
  39.       }
  40.       else
  41.       {
  42.          throw new Exception('Undefined property [' . $prop . ']',1);
  43.       }
  44.    }
  45.    
  46.    public static function __get($prop)
  47.    {
  48.  
  49.       if (isset(self::$_instance->$prop))
  50.       {
  51.          switch ($prop)
  52.          {
  53.             case 'isDebugging':
  54.                return self::$_instance->isDebugging;
  55.                break;
  56.             
  57.             default :
  58.                throw new Exception('Cannot read property [' . $prop . ']',1);
  59.          }
  60.  
  61.       }
  62.       else
  63.       {
  64.          throw new Exception('Undefined property [' . $prop . ']',1);
  65.       }
  66.    } 
  67.  
  68.  
  69. }
  70. ?>

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

  1. <?php
  2.    include 'config.inc.php';
  3.    
  4.    // First reference
  5.    $myConfig1 = Config::getInstance();
  6.    
  7.    // Get property
  8.    echo ('$myConfig1->isDebugging:' . ($myConfig1->isDebugging ? "true" : "false")) . '<br/>';
  9.    // Set property
  10.    echo 'Set $myConfig1->isDebugging = true <br/>';
  11.    $myConfig1->isDebugging = true;
  12.    echo ('$myConfig1->isDebugging:' . ($myConfig1->isDebugging ? "true" : "false")) . '<br/>';
  13.    
  14.    // Second reference
  15.    echo '<br/>';
  16.    echo 'Add second reference and not getInstance args<br/>';
  17.    echo '$myConfig2 = Config::getInstance(); <br/>';
  18.    $myConfig2 = Config::getInstance();
  19.    
  20.    echo ('$myConfig1->isDebugging:' . ($myConfig1->isDebugging ? "true" : "false")) . '<br/>';
  21.    echo ('$myConfig2->isDebugging:' . ($myConfig2->isDebugging ? "true" : "false")) . '<br/>';
  22.    
  23.    // Third reference
  24.    echo '<br/>';
  25.    echo 'Add third reference and change prop via getInstance arg <br/>';
  26.    echo '$myConfig3 = Config::getInstance(array(\'isDebugging\'=>false)); <br/>';
  27.    $myConfig3 = Config::getInstance(array('isDebugging'=>false));
  28.    echo ('$myConfig1->isDebugging:' . ($myConfig1->isDebugging ? "true" : "false")) . '<br/>';
  29.    echo ('$myConfig2->isDebugging:' . ($myConfig2->isDebugging ? "true" : "false")) . '<br/>';
  30.    echo ('$myConfig3->isDebugging:' . ($myConfig3->isDebugging ? "true" : "false")) . '<br/>';
  31.    
  32.    // Set property via second instance
  33.    echo '<br/>';
  34.    echo 'Set property via second instance <br/>';
  35.    echo 'Set $myConfig2->isDebugging = true <br/>';
  36.    $myConfig2->isDebugging = true;
  37.    echo ('$myConfig1->isDebugging:' . ($myConfig1->isDebugging ? "true" : "false")) . '<br/>';
  38.    echo ('$myConfig2->isDebugging:' . ($myConfig2->isDebugging ? "true" : "false")) . '<br/>';
  39.    echo ('$myConfig3->isDebugging:' . ($myConfig3->isDebugging ? "true" : "false")) . '<br/>';
  40.    
  41.    
  42.    
  43.    // Set property to incorrect data type
  44.    echo '<br/>';
  45.    echo 'Set $myConfig1->isDebugging = 123<br/>';
  46.    echo 'No exception for invalid data type and not prop change.<br/>';
  47.    $myConfig1->isDebugging = 123;
  48.    echo ('$myConfig1->isDebugging:' . ($myConfig1->isDebugging ? "true" : "false")) . '<br/>';
  49.    echo ('$myConfig2->isDebugging:' . ($myConfig2->isDebugging ? "true" : "false")) . '<br/>';
  50.    echo ('$myConfig3->isDebugging:' . ($myConfig3->isDebugging ? "true" : "false")) . '<br/>';
  51.  
  52.    // Setter throws undefined property exception
  53.    //$myConfig1->test = true;
  54.    // Getter throws undefined property exception
  55.    //echo '$myConfig1->test:' . $myConfig1->test . '<br/>';
  56.    // Setter throws cannot write property exception
  57.    //$myConfig1->version = '2.2';
  58.    // Setter throws cannot read property exception
  59.    //echo '$myConfig1->cannotReadProp:' . $myConfig1->cannotReadProp . '<br/>';
  60.    
  61. ?>

By Lon Hosford Add comment


Recent Blog Posts

Categories

Blogroll