如何使用PHP5类创建Singleton类?
/** * 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;
工作原理.
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的实例.
不幸的是,当有多个子类时,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";
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