Php 扩展抽象单例类
如果您有一个创建某种新对象的factory类,而factroy类是一个单例,如下所示:Php 扩展抽象单例类,php,singleton,abstract-class,Php,Singleton,Abstract Class,如果您有一个创建某种新对象的factory类,而factroy类是一个单例,如下所示: class Database_Factory extends Base_Factory { private static $factory; private $objects = array(); public function __get($profile) { // check for object and return it if it's created be
class Database_Factory extends Base_Factory {
private static $factory;
private $objects = array();
public function __get($profile) {
// check for object and return it if it's created before
}
public static function getInstance(){
if (!self::$factory)
self::$factory = new self();
return self::$factory;
}
}
当某个对象需要自己的工厂时,相同的代码随时重复。所以我决定将这个工厂类抽象化,只为每个工厂实现特定的例程。但是PHP不允许实例化抽象类
abstract class Base_Factory {
public static function getInstance(){
if (!self::$factory)
self::$factory = new self();
return self::$factory;
}
}
致命错误:无法实例化抽象类基类工厂
你会怎么做?你可以做一个检查,确保调用函数的类不是基工厂
if(__CLASS__!='Base_Factory')
然后使用$this而不是self来引用当前对象而不是当前类
if (!$this->factory)
$this->factory = new self();
return $this->factory;
根据定义,抽象类不能像任何其他面向对象语言一样在PHP中实例化。因此,您的基本工厂应该是接口,而不是抽象类
abstract class Base_Factory {
public static function getInstance(){
if (!self::$factory)
self::$factory = new self();
return self::$factory;
}
}
来自PHP手册:“不允许创建已定义为抽象类的类的实例。”PHP>=5.3
abstract class Base_Factory {
protected static $factory;
public static function getInstance(){
if (!self::$factory) {
$class = get_called_class();
self::$factory = new $class();
}
return self::$factory;
}
}
在PHP方法中,
self
总是指定义方法的类。从5.3.0版开始,PHP支持“后期静态绑定”,在这里,您可以使用static
关键字访问重写的静态方法,以及函数get\u called\u class()
在静态上下文中获取派生类的名称
但是,您的设计有一个主要缺陷:在Base\u factory
中定义的静态属性$factory
在所有派生类中共享。因此,第一次在此属性中创建和存储单例时,对getInstance()
的所有其他调用都将返回相同的对象,无论使用什么派生类
可以使用静态字典将类名映射到单例对象:
abstract class Base_Factory {
private static $_instances = array();
public static function getInstance() {
$class = get_called_class();
if (!isset(self::$_instances[$class])) {
self::$_instances[$class] = new $class();
}
return self::$_instances[$class];
}
}
哦,还有一件事:您正在寻找为单例对象重用代码的可能性,这一事实可能暗示您过度使用了单例设计模式!问问自己,您计划作为单例实现的类是否真的是单例类,以及是否没有您可能希望拥有特定类的多个实例的用例
通常,最好只使用一个表示当前“应用程序上下文”的单例,该上下文为与此上下文相关的单例对象提供访问器。在这样一个简单的类中注册单例
class Singletons {
static private $singleton = array();
public function getSingleton($class) {
if (!isset(self::$singleton[$class])) {
self::$singleton[$class] = new $class;
}
return self::$singleton[$class];
}
}
那就这样做吧
class aSingleton {
public $i;
public function test() {
++$this->i;
echo get_class() . " called {$this->i} times\n";
}
}
Singletons::getSingleton('aSingleton')->test();
Singletons::getSingleton('aSingleton')->test();
输出
aSingleton called 1 times
aSingleton called 2 times
PHP5.3+
abstract class Singleton
{
/**
* Instance
*
* @var Singleton
*/
protected static $_instance;
/**
* Constructor
*
* @return void
*/
protected function __construct() {}
/**
* Get instance
*
* @return Singleton
*/
public final static function getInstance() {
if (null === static::$_instance) {
static::$_instance = new static();
}
return static::$_instance;
}
}
静态函数没有
$this
。此外,\uuuuuuu CLASS\uuuuuu
始终表示定义函数的类,在您的情况下,即使在派生类中,它也将始终是“基本工厂”。啊,对不起,您的权利,您甚至不能使用get\u类($this)作为替代方法。问题本质上是:我如何从编写这些getInstance中解放出来(也许以后还会有更多)每个工厂中的函数?Mark似乎知道他不能实例化他的抽象基类。Hew希望从抽象基类中定义的代码中动态实例化派生的非抽象类。是的,Ferdinand,这很准确。谢谢,但不幸的是,目前我的共享主机上没有PHP>=5.3。但是我将保留这段代码,以备将来使用:)。您忘记将$\u实例声明为静态实例,并且您对LSB的解释是正确的,但是您建议了一种解决方案,首先实现LSB:)他的代码可以与LSB一起使用,您只需在父类中重新声明静态实例。回答得很好,谢谢!我之所以希望这样做,是因为我正在创建自己的框架来运行一系列不同的应用程序。根据我的推理,如果我有两个单件,那就是复制和粘贴太多了。我宁愿创建一个抽象类并进行扩展。然后,根据我读到的一些观点,如果我意识到我在大胆使用单身模式方面的错误恐惧,那么改变就更容易了;)可能您必须有一个静态成员变量来跟踪单个aSingleton实例。那么,我们为什么要创建一个像@FerdinandBeyer接受的答案中那样的词典呢?我认为只有当我们需要来自同一个抽象类的许多单例实例时,对吗?Update:或者在PHP5.3中,原因与公认答案中描述的相同。self::$factory将在实例化任何派生类后定义。第一个实例将在所有派生类之间共享