当前位置:  开发笔记 > 编程语言 > 正文

在PHP5中创建Singleton设计模式

如何解决《在PHP5中创建Singleton设计模式》经验,为你挑选了10个好方法。

如何使用PHP5类创建Singleton类?



1> 小智..:
/**
 * Singleton class
 *
 */
final class UserFactory
{
    /**
     * Call this method to get singleton
     *
     * @return UserFactory
     */
    public static function Instance()
    {
        static $inst = null;
        if ($inst === null) {
            $inst = new UserFactory();
        }
        return $inst;
    }

    /**
     * Private ctor so nobody else can instantiate it
     *
     */
    private function __construct()
    {

    }
}

使用:

$fact = UserFactory::Instance();
$fact2 = UserFactory::Instance();

$fact == $fact2;

但:

$fact = new UserFactory()

引发错误.

请参阅http://php.net/manual/en/language.variables.scope.php#language.variables.scope.static以了解静态变量范围以及设置的static $inst = null;工作原理.


要比较你应该使用的两个实例===而不是==.如果$ fact1和$ fact2都是同一个类,则==将返回true,但如果它们都是同一个对象的同一个实例,则===只返回true.
每次调用Instance()时,此方法都不会将UserFactory实例重置为null吗?在java中,$ inst变量将是一个私有静态属性,不应该反复重置,否则你也可能不会使它成为单例.
clone方法也应该是私有的
你应该使用$ inst = new self(); 不是$ inst = new UserFactory(); 对于后来遇到此事的人 +1使用内置的PHP方法.
这里有一个很好的说明为什么以及如何在函数中将变量声明为静态,如作者所希望的那样:http://php.net/manual/en/language.variables.scope.php#language.variables.scope.static
我不明白为什么静态$ inst = null; 在以后的电话中被"忽略".看代码我会说代码,if($ inst === null)被调用,但不是.为什么?
在Inside()中声明$ inst的原因是什么?
我们不需要重写__clone()和__wakeup()方法来触发错误并停止克隆和反序列化(如果它是Singleton)吗?
是的,不应该静态$ inst = null; 在类体中声明而不是Instance()方法?

2> selfawaresou..:

PHP 5.3允许通过后期静态绑定创建可继承的Singleton类:

class Singleton
{
    protected static $instance = null;

    protected function __construct()
    {
        //Thou shalt not construct that which is unconstructable!
    }

    protected function __clone()
    {
        //Me not like clones! Me smash clones!
    }

    public static function getInstance()
    {
        if (!isset(static::$instance)) {
            static::$instance = new static;
        }
        return static::$instance;
    }
}

这解决了这个问题,在PHP 5.3之前,任何扩展Singleton的类都会生成其父类的实例而不是它自己的实例.

现在你可以这样做:

class Foobar extends Singleton {};
$foo = Foobar::getInstance();

$ foo将是Foobar的一个实例,而不是Singleton的实例.


当有多个子类时,这不起作用!`$ instance`驻留在Singleton中,而不是子类.在实例化一些子类之后,getInstance()将为所有子类返回该实例.
来自@ggsonic:``子类应该拥有自己的静态var.检查一下:echo get_class(Foobar :: getInstance()); echo get_class(Singleton :: getInstance());"`.
这根本不起作用,Foobar是你构建的第一堂课吗?

3> mpartel..:

不幸的是,当有多个子类时,Inwdr的答案会中断.

这是一个正确的可继承Singleton基类.

class Singleton
{
    private static $instances = array();
    protected function __construct() {}
    protected function __clone() {}
    public function __wakeup()
    {
        throw new Exception("Cannot unserialize singleton");
    }

    public static function getInstance()
    {
        $cls = get_called_class(); // late-static-bound class name
        if (!isset(self::$instances[$cls])) {
            self::$instances[$cls] = new static;
        }
        return self::$instances[$cls];
    }
}

测试代码:

class Foo extends Singleton {}
class Bar extends Singleton {}

echo get_class(Foo::getInstance()) . "\n";
echo get_class(Bar::getInstance()) . "\n";



4> Abraham Tuga..:

Real One和现代制作Singleton Pattern的方法是:



所以现在你可以像使用它一样.

label = $label;
  }

  public function getLabel()
  {
    return $this->label;
  }

}

// create first instance
$database = Database::instance();
$database->setLabel('Abraham');
echo $database->getLabel() . PHP_EOL;

// now try to create other instance as well
$other_db = Database::instance();
echo $other_db->getLabel() . PHP_EOL; // Abraham

$other_db->setLabel('Priler');
echo $database->getLabel() . PHP_EOL; // Priler
echo $other_db->getLabel() . PHP_EOL; // Priler

如您所见,这种实现更加灵活.


这是关于此线程中Singleton模式的最清晰答案.谢谢.

5> Stefan Gehri..:

您可能应该添加一个私有__clone()方法来禁止克隆实例.

private function __clone() {}

如果您不包含此方法,则可以进行以下操作

$inst1=UserFactory::Instance(); // to stick with the example provided above
$inst2=clone $inst1;

现在$inst1!== $inst2- 他们不再是同一个实例了.



6> jose segura..:


使用:

/**
 *  example of class definitions using SingletonTrait
 */
class DBFactory {
  /**
   * we are adding the trait here 
   **/
   use SingletonTrait;

  /**
   * This class will have a single db connection as an example
   **/
  protected $db;


 /**
  * as an example we will create a PDO connection
  **/
  protected function __construct(){
    $this->db = 
        new PDO('mysql:dbname=foodb;port=3305;host=127.0.0.1','foouser','foopass');
  }
}
class DBFactoryChild extends DBFactory {
  /**
   * we repeating the inst so that it will differentiate it
   * from UserFactory singleton
   **/
   protected static $inst = null;
}


/**
 * example of instanciating the classes
 */
$uf0 = DBFactoryChild::getInstance();
var_dump($uf0);
$uf1 = DBFactory::getInstance();
var_dump($uf1);
echo $uf0 === $uf1;

respose:

object(DBFactoryChild)#1 (0) {
}
object(DBFactory)#2 (0) {
}

如果您使用的是PHP 5.4:trait它的一个选项,那么您不必浪费继承层次结构以获得Singleton模式

并且还注意到,如果不添加以下代码行,是否使用特征扩展Singleton类的松散结束是创建子类的单例:

   protected static $inst = null;

在儿童班

意外的结果将是:

object(DBFactoryChild)#1 (0) {
}
object(DBFactoryChild)#1 (0) {
}



7> hungneox..:
protected  static $_instance;

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

此代码可以适用于任何类,而无需关心其类名.



8> RobertPitt..:
支持多个对象,每个类1行:

这个方法会在你想要的任何类上强制执行单例,你需要做的就是在你想要制作单例的类中添加1个方法,这样就可以为你完成.

这也将对象存储在"SingleTonBase"类中,因此您可以通过递归SingleTonBase对象来调试系统中使用的所有对象.


创建一个名为SingletonBase.php的文件,并将其包含在脚本的根目录中!

代码是

abstract class SingletonBase
{
    private static $storage = array();

    public static function Singleton($class)
    {
        if(in_array($class,self::$storage))
        {
            return self::$storage[$class];
        }
        return self::$storage[$class] = new $class();
    }
    public static function storage()
    {
       return self::$storage;
    }
}

然后对于任何想要制作单例的类,只需添加这个小的单个方法.

public static function Singleton()
{
    return SingletonBase::Singleton(get_class());
}

这是一个小例子:

include 'libraries/SingletonBase.resource.php';

class Database
{
    //Add that singleton function.
    public static function Singleton()
    {
        return SingletonBase::Singleton(get_class());
    }

    public function run()
    {
        echo 'running...';
    }
}

$Database = Database::Singleton();

$Database->run();

你可以在你拥有的任何类中添加这个单例函数,它只会为每个类创建1个实例.

注意:您应该始终使__construct为private以消除使用新的Class(); 实例.



9> rizon..:
class Database{

        //variable to hold db connection
        private $db;
        //note we used static variable,beacuse an instance cannot be used to refer this
        public static $instance;

        //note constructor is private so that classcannot be instantiated
        private function __construct(){
          //code connect to database  

         }     

         //to prevent loop hole in PHP so that the class cannot be cloned
        private function __clone() {}

        //used static function so that, this can be called from other classes
        public static function getInstance(){

            if( !(self::$instance instanceof self) ){
                self::$instance = new self();           
            }
             return self::$instance;
        }


        public function query($sql){
            //code to run the query
        }

    }


Access the method getInstance using
$db = Singleton::getInstance();
$db->query();



10> DevWL..:

您实际上不需要使用Singleton模式,因为它被认为是反模式。基本上,有很多理由根本不执行此模式。请阅读以下内容:PHP单例类的最佳实践。

如果毕竟您仍然认为您需要使用Singleton模式,那么我们可以编写一个类,该类将通过扩展SingletonClassVendor抽象类来获得Singleton功能。

这就是我用来解决这个问题的方法。



使用示例:

/**
 * EXAMPLE
 */

/**
 *  @example 1 - Database class by extending SingletonClassVendor abstract class becomes fully functional singleton
 *  __constructor must be set to protected becaouse: 
 *   1 to allow instansiation from parent class 
 *   2 to prevent direct instanciation of object with "new" keword.
 *   3 to meet requierments of SingletonClassVendor abstract class
 */
class Database extends SingletonClassVendor
{
    public $type = "SomeClass";
    protected function __construct(){
        echo "DDDDDDDDD". PHP_EOL; // remove this line after testing
    }
}


/**
 *  @example 2 - Config ...
 */
class Config extends SingletonClassVendor
{
    public $name = "Config";
    protected function __construct(){
        echo "CCCCCCCCCC" . PHP_EOL; // remove this line after testing
    }
}

只是为了证明它能按预期工作:

/**
 *  TESTING
 */
$bd1 = Database::getInstance(); // new
$bd2 = Database::getInstance(); // old
$bd3 = Config::getInstance(); // new
$bd4 = Config::getInstance(); // old
$bd5 = Config::getInstance(); // old
$bd6 = Database::getInstance(); // old
$bd7 = Database::getInstance(); // old
$bd8 = Config::getInstance(); // old

echo PHP_EOL."COMPARE ALL DATABASE INSTANCES".PHP_EOL;
var_dump($bd1);
echo '$bd1 === $bd2' . ($bd1 === $bd2)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
echo '$bd2 === $bd6' . ($bd2 === $bd6)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
echo '$bd6 === $bd7' . ($bd6 === $bd7)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE

echo PHP_EOL;

echo PHP_EOL."COMPARE ALL CONFIG INSTANCES". PHP_EOL;
var_dump($bd3);
echo '$bd3 === $bd4' . ($bd3 === $bd4)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
echo '$bd4 === $bd5' . ($bd4 === $bd5)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
echo '$bd5 === $bd8' . ($bd5 === $bd8)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE

推荐阅读
农大军乐团_697
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有