开发者

Creating singleton - is this really right?

开发者 https://www.devze.com 2023-02-10 05:56 出处:网络
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

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 c开发者_C百科urrent 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();


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.


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...


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;
   }

}


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消