创建单身人士 - 这是真的吗?

时间:2011-02-14 22:18:10

标签: php oop design-patterns singleton

我正在尝试创建我自己的轻量级但OOP方式来跟踪我的PHP框架中加载的文件及其相应的版本(尚未实现),以便能够在将来轻松测试依赖性问题。

这是我目前的代码,但作为OOP和模式的新手,我无法确定我是否已经完成了正确的单例:

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();

4 个答案:

答案 0 :(得分:2)

不,它不是单身人士。实际上你只是在玩静态属性。单身人更像是这样:

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');

我不知道你是否可以在PHP中将构造函数设置为私有......我认为不是。

静态类 $ 和单例之间存在差异。单例允许一次只有一个实例。对于静态类,您甚至不需要实例。此外,静态属性在类的所有实例之间共享(如果您创建实例)。

如果您不需要实例来保存某个状态,则通常使用静态类。

$:没有真正的静态类。只有成员才能被定义为静态。我会说一个只有静态成员的类可以称为静态类。

答案 1 :(得分:2)

您在上面提到的内容并不遵循Singleton的模式。 Singleton只允许一次存在该类的一个实例(而不是定义一个静态对象,这不会阻止您创建同时的其他对象并使它们混淆)。

您可以在官方手册中阅读PHP中的Singleton模式; http://php.net/manual/en/language.oop5.patterns.php

上面的手动示例给出了一个准系统示例,但我从未真正需要在PHP中使用Singleton,因为PHP5已经发布。它们在诸如iPhone之类的设备上更有用,在这些设备上你只需要一个特定硬件的单一接口 - 例如屏幕。但是,我想你可能会在PHP应用程序中将它用于数据库连接......

答案 2 :(得分:1)

这段代码看起来很奇怪 - 首先,构造函数永远不会被任何内部函数调用,因为它是私有的,所以不能在外部调用。它不是单身,因为单身实际上意味着被创建为一个对象,而这个类永远不会。

但是,您可以使用此类代码创建分区全局存储,如果这是您想要的。

这是给你的单身人士:

class Singleton {
   private static $me;

   private function __construct 
   { 
       /* something */ 
   }

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

}

这里改进了5.3+单身:

class Singleton {
   private static $me;

   private function __construct 
   { 
      /* something */ 
   }

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

}

答案 3 :(得分:0)

我觉得这有点旧了。

我曾经仅仅为了单个实例使用单例,但是使用注册表你不再需要静态。 另一方面,如何实现和使用注册表来定义注册表解决方案是否良好。

因为我使用MVC并且只需要为基本控制器传递一次注册表,为基本模型传递一次,这就是全部。另一方面,如果一个设计需要经常传递注册表对象,那么它可能不是一个好主意。

基本理念是:

  1. 有一个注册表

  2. 刚开始时只创建了一个数据库类的实例,这样我们就不用费心去创建连接等了。我使用了两个数据库,直到我第一次需要它时才创建连接

    $ registry-> dbManager = new dbManager();

  3. 将注册表对象传递给路由器,控制器和模型基类注册表随处可见 $ registry = My_Registry :: singleton(); $ registry-> router = new router($ registry); $ registry-> dbManager = new dbManager(); 等..................

  4. Db类保持正常类,这只是db类的一部分

    类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'连接到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
    

    .......................等....

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

    .................等

  5. 这就是我从db class

    调用公共函数的方法

    //查询数据库
    $结果= $这 - >登记处送交> dbManager-> uniqueRowExists ('Internal','internal_user',Array('uname','pass'),$ input); //连接可供选择,表格,颜色,数组搜索数据

  6. 这样在任何地方只有一个实例。