如何实例化抽象类的子单例?

时间:2015-05-22 04:32:55

标签: php singleton abstract-class

我有一个抽象类和一个扩展抽象类的子代。孩子应该是个傻瓜。以下是抽象类的简化示例:

abstract class AbstractClass{
    protected static $instance = NULL;
    abstract protected function meInit();

    private function __construct(){
        $this->meInit();
        $this->init();
    }

    private function __clone(){}

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

    function init(){
        'code here;

    }
}

这是简化的子类:

class ChildClass_A extends AbstractClass{

    protected function meInit(){
        'some code;
    }
}

当我尝试获取孩子$child = ChildClass_A::getInstance();的实例时,我收到此错误:

  

致命错误:无法实例化抽象类AbstractClass   第7行的C:\ wamp \ www \ Classes \ AbstractClass.php

我怀疑罪魁祸首在self::$instance=new self;。我该如何重做以达到我的需要?

1 个答案:

答案 0 :(得分:8)

你快到了;你不能像这样使用new self(),因为它试图做new A()。相反,请使用get_called_class(),以便创建新的B

// ONLY SUPPORTS ONE SUBCLASS
// KEEP READING BELOW FOR COMPLETE SOLUTION
abstract class A {

    static protected $instance = null;

    abstract protected function __construct();

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

}

class B extends A {
    protected function __construct() {
        echo "constructing B\n";
    }
}

var_dump(B::getInstance()); // constructing B, object(B)#1 (0) {}
var_dump(B::getInstance()); // object(B)#1 (0) {}

好的,但是当我们尝试创建另一个子类时会发生什么?

class C extends A {
    protected function __construct() {
        echo "constructing C\n";
    }
}

var_dump(C::getInstance()); // object(B)#1 (0) {}
var_dump(C::getInstance()); // object(B)#1 (0) {}

那太糟糕了!我想要一个C个实例,而不是B个实例!这是因为抽象类 A 只保存一个实例。我们必须使它支持每个子类中的一个。

那很容易!

// SOLUTION:
// WORKS FOR MULTIPLE SUBCLASSES
abstract class A {

    static protected $instances = array();

    abstract protected function __construct();

    static public function getInstance() {
        $class = get_called_class();
        if (! array_key_exists($class, self::$instances)) {
            self::$instances[$class] = new $class();
        }
        return self::$instances[$class];
    }

}

班级BC可以保持不变......

class B extends A {
    protected function __construct() {
        echo "constructing B\n";
    }
}

class C extends A {
    protected function __construct() {
        echo "constructing C\n";
    }
}

现在让我们看看他们的行为

var_dump(B::getInstance()); // constructing B, object(B)#1 (0) {}
var_dump(B::getInstance()); // object(B)#1 (0) {}

var_dump(C::getInstance()); // constructing C, object(C)#2 (0) {}
var_dump(C::getInstance()); // object(C)#2 (0) {}
好的,好的!正是我们一直想要的!