0

I am trying to create my own sort of lightweight,yet OOP way to keep track of loaded files and their appropriate versions (not yet implemented) in my PHP framework to be able to easily test dependency issues in the future.

Here's my current code, but being a total newcomer to OOP and patterns I am not able to determine if I have accomplished a proper Singleton or not:

class loadRegistry {

    private static $registry = null;

    private function __construct(){

        if (is_null(self::$registry));
        self::$registry = array();

    }

    public static function get() {
        return self::$registry;
    }

    public static function set($filename){

        if ( isSet( self::$registry[$filename]) AND !empty($filename) ) {
            throw new Exception("File already loaded");
        }
        else self::$registry[$filename] = '';
    }

}

loadRegistry::set('filename');
loadRegistry::set('filename2');

$reg = loadRegistry::get();
hakre
  • 178,314
  • 47
  • 389
  • 754
Industrial
  • 36,181
  • 63
  • 182
  • 286
  • That is not a singleton. I'm not sure what it is trying to be... It almost looks like an abstract factory, but I don't see where objects are dealt with. Not to mention you could just do `private static $registry = array()` and save the is_null check... And you have no way of instantiating it, so there's no registry anyway... – ircmaxell Feb 14 '11 at 22:23
  • 4
    You might want to have a read of [Static methods vs singletons: choose neither](http://www.phparch.com/2010/03/static-methods-vs-singletons-choose-neither/). – John Parker Feb 14 '11 at 22:26
  • 1
    *(related)* [Why Singletons have no use in PHP](http://gooh.posterous.com/singletons-in-php) is the longer version of my answer to [Who needs Singletons](http://stackoverflow.com/questions/4595964/who-needs-singletons/4596323#4596323) – Gordon Feb 14 '11 at 22:38
  • 1
    @Gordon: Thanks a lot for the heads up! – Industrial Feb 14 '11 at 22:40
  • you're welcome. The link provided by @middaparka is a good one too. – Gordon Feb 14 '11 at 22:43

4 Answers4

2

No, it is not a singleton. You are actually only playing with static properties. A singleton would be more like this:

class Registry {

    private static $registry = null;
    private $data;

    private function __construct(){
        $this->data = array();
    }

    public static function getInstance() {
        if (is_null(self::$registry)) {
            self::$registry = new Registry();
        }
        return self::$registry;
    }

    public function set($filename){
        if (isset($this->data[$filename]) && !empty($filename) ) {
            throw new Exception("File already loaded");
        }
        else {
            $this->data[$filename] = '';
        }
    }

    // further **instance** methods
}

$reg = Registry::getInstance();
$reg->set('filename');
$reg->set('filename2');

I don't know whether you can set the constructor as private in PHP... I think not.

There is a difference between static classes$ and a singleton. A singleton allows to have only one instance at a time. For static classes, you don't even need an instance. In addition, static properties are shared between all instances of the class (in case you create an instance).

You normally use static classes if you don't need an instance to hold some state.

$: There are no real static classes. Only members can be defined as static. I'd say a class that has only static members can be called a static class.

Felix Kling
  • 705,106
  • 160
  • 1,004
  • 1,072
  • set function should not be static. – Jacob Feb 14 '11 at 22:31
  • Private constructor will parse and cause fatal error when instantiation is attempted. – webbiedave Feb 14 '11 at 22:32
  • 1
    @webbie: that's what you want, since the whole point of a singleton is to prevent instantiation from outside of the class itself (so `getInstance` is the only way to instantiate the class)... The constructor should be `private function __construct`, otherwise it's not a singleton... – ircmaxell Feb 14 '11 at 22:36
  • @ircmaxwell: I was just answering verbosely for Felix. – webbiedave Feb 14 '11 at 23:01
  • For true singleton you should also overwrite the __clone() function. – Leon Feb 15 '11 at 08:47
2

What you have presented above isn't following the pattern of a Singleton. A Singleton allows only a single instance of that class to exist at one time (as opposed to defining a Static object, which doesn't stop you from then creating other objects of the same time and getting them mixed up).

You can read about the Singleton Pattern in PHP in the official manual; http://php.net/manual/en/language.oop5.patterns.php

The manual example above gives a barebones example, but I've never really had the need to use a Singleton in PHP since PHP5 has been released. They are more useful on the devices such as the iPhone where you only want a single interface to a given piece of hardware - such as the screen. However, I guess you might use it for your DB connections in a PHP app...

John Wordsworth
  • 2,541
  • 1
  • 17
  • 24
1

This code looks strange - first of all, the constructor is never called by any of the internal functions and can't be called externally since it's private. It's not a singleton since singleton is actually meant to be created as an object, while this class is never is.

You can, however, use code like this for creating compartmentalized global storage, if that is what you wanted to do.

Here's a singleton for you:

class Singleton {
   private static $me;

   private function __construct 
   { 
       /* something */ 
   }

   public static getInstance() 
   {
      if(empty(self::$me)) self::$me = new self;
      return self::$me;
   }

}

Here's improved 5.3+ singleton:

class Singleton {
   private static $me;

   private function __construct 
   { 
      /* something */ 
   }

   public static getInstance() 
   {
      if(empty(self::$me)) self::$me = new static;
      return self::$me;
   }

}

StasM
  • 9,840
  • 5
  • 49
  • 96
0

I see this is a bit old however..

I used to use singleton just for the sake of single instance, however with registry you don't need a static anymore. On the other hand is how registry is implemented and used that will define if the registry solution is good.

Because I use MVC and only have to pass the registry once for the base controller and once for the base model and that's it all. On the other hand if one has a design that requires for passing the registry object very often the it might not be a good idea.

The basic idea is:

  1. There is a registry

  2. At the very begining is created just an instance of the database class, this way we don't bother with creating connections etc. I use two databases and no connection is created until the veri first time I will need it.

    $registry->dbManager = new dbManager();

  3. Passing the registry object to the router, controller and model base classes registry is seen everywhere.
    $registry = My_Registry::singleton(); $registry->router = new router($registry); $registry->dbManager = new dbManager(); etc..................

  4. Db class stays normal class, this is just a part from the db class

    class dbManager {

    //DB Connections
    private  $Internal_db_con = null;
    private  $Business_db_con = null;
    
    //DB Connection Parameters
    private  $host=null;
    private  $user=null;
    private  $pass=null;
    
    //DB Names
    private  $internal_db_name=null;
    private  $business_db_name=null;    
    
    //
    private $result = null;
    
    
    
    //   only one object created
    public  function __construct()
    { 
            include_once __SITE_PATH . 'includes/db_config.inc';
    

    list($this->host,$this->user, $this->pass, $this->internal_db_name,$this->business_db_name ) = $db_conf;

    }
    
    
    
    
    //set  internal database connection
    private function setInternalDBCon()
    { debug('setInternalDBCon called');
                try{    
                    # MySQL with PDO_MYSQL  
                    $dbq="\"";
                    $this->Internal_db_con = new 
    

    PDO("mysql:host=".$this->host.";dbname=".$this->internal_db_name ,$this->user, $this->pass, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));

    $this->Internal_db_con->setAttribute (PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
                    }  
                catch(PDOException $e) 
                {  
                echo 'Error connecting to MySQL: ' .$e->getMessage();  
                }    
    
    }
    
    
    
    
    
    
    //set  business database connection
    public  function setBusinessDBCon()
    { 
                try{    
                # MySQL with PDO_MYSQL  
                $dbq="\"";
                $this->Business_db_con = new 
    

    PDO("mysql:host=".$this->host.";dbname=".$this->internal_db_name ,$this->user, $this->pass, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));

    $this->Business_db_con->setAttribute (PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); }
    catch(PDOException $e) {
    echo 'Error connecting to MySQL: ' .$e->getMessage();
    }

    }
    
    
    
    
    
    
    /*check if a row exists in a safe way that avoids sql atack*/
    public  function uniqueRowExists($dbcon, $table,$col_name, $data)
    {    
            //check if connection is set 
            if($this->{$dbcon.'_db_con'}==null) //dynamic variable call
        $this->callMyFunc( 'set'.$dbcon.'DBCon');  //dynamic function call
    

    .......................etc....

            //prepare
            $stmt =  $this->{$dbcon.'_db_con'}->prepare($sql);
        $stmt->execute($data);
    

    .................etc

  5. And this is how I call a public function from db class

    //query the database
    $result=$this->registry->dbManager->uniqueRowExists ('Internal', 'internal_user', Array('uname','pass'), $input); //connection to choose from, table, coloumns, array data to search for

this way there is only a single instance anywhere.

Melsi
  • 1,424
  • 15
  • 19