扩展抽象单例类

时间:2009-11-30 09:31:34

标签: php singleton abstract-class

如果你有一个工厂类来创建某种类型的新对象,那个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;
    }
}

致命错误:无法实例化抽象类Base_Factory

你会做什么?

6 个答案:

答案 0 :(得分:36)

在PHP方法中,self始终引用定义方法的类。从5.3.0版本开始,PHP支持“后期静态绑定”,您可以使用static关键字来访问重写的静态方法,以及使用函数get_called_class()来获取派生类的名称。静态背景。

但是,您的设计存在一个主要缺陷:$factory中定义的静态属性Base_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];
    }
}

哦,还有一件事:您正在寻找重新使用单例对象代码的可能性,这可能是您过度使用单例设计模式的一个事实!问问自己,你计划作为单身人士实施的课程是否真的是单身,如果没有用例,你可能想要拥有特定课程的多个实例。

通常情况下,只使用一个表示当前“应用程序上下文”的单例更好,它为与此上下文相关的单例对象提供访问器。

答案 1 :(得分:8)

PHP 5.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;
    }
}

答案 2 :(得分:4)

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;
    }
}

答案 3 :(得分:1)

在像这样的简单课程中注册您的单身人士

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

答案 4 :(得分:-1)

根据定义,抽象classess不能像任何其他面向对象的语言一样在PHP中实例化。所以你的Base_Factory应该是接口而不是抽象类。

从PHP手册:“不允许创建已定义为抽象的类的实例。”

答案 5 :(得分:-2)

您可以检查以确保调用该函数的类不是Base_Factory。

if(__CLASS__!='Base_Factory')

然后使用$ this而不是self来引用当前对象而不是当前类。

if (!$this->factory)
        $this->factory = new self();
    return $this->factory;