Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 扩展抽象单例类_Php_Singleton_Abstract Class - Fatal编程技术网

Php 扩展抽象单例类

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

如果您有一个创建某种新对象的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 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将在实例化任何派生类后定义。第一个实例将在所有派生类之间共享