我有一个主要类,其中包含单例函数 instance()和关联变量 $ instance 。现在我创建了几个子类,让主类继承。由于有用的继承,我没有重新定义单例函数和变量。不幸的是,每个实例都指向第一个子类。只有在子类中 $ instance 变量初始化为 null 时才有效,但为什么呢?使用关键字静态而非自我,范围应保留在子类中。
以下是更好地理解我的意思的源代码:
// PHP Version 7.0
// Don't work as expected:
class base1
{
/*
* Instance of class
* mixed
*/
protected static $instance = null;
/*
* For Singleton Pattern
*/
public static function instance() {
if ( null == static::$instance ) {
static::$instance = new static();
}
return static::$instance;
}
public function test()
{
$test = "base1";
var_dump($test);
}
}
class sub11 extends base1
{
public function test()
{
$test = "base1 -> sub11";
var_dump($test);
}
}
class sub12 extends base1
{
public function test()
{
$test = "base1 -> sub12";
var_dump($test);
}
}
$sub11 = sub11::instance();
$sub12 = sub12::instance();
$sub11->test();
$sub12->test();
// Output:
// string(14) "base1 -> sub11"
// string(14) "base1 -> sub11" // It's not different!!!
// Work as expected:
class sub21 extends base1
{
/*
* Instance of class
* mixed
*/
protected static $instance = null; // Is needed, but why?
public function test()
{
$test = "base1 -> sub21";
var_dump($test);
}
}
class sub22 extends base1
{
/*
* Instance of class
* mixed
*/
protected static $instance = null; // Is needed, but why?
public function test()
{
$test = "base1 -> sub22";
var_dump($test);
}
}
$sub21 = sub21::instance();
$sub22 = sub22::instance();
$sub21->test();
$sub22->test();
// Output:
// string(14) "base1 -> sub21"
// string(14) "base1 -> sub22" // This is correct !
答案 0 :(得分:3)
在您的第一部分中,它正在按照预期正确正确。两个类 sub11 和 sub12 使用 base1 的字段来存储实例。因此,第一个被实例化的,放在那里,防止其他人覆盖已经创建的实例。
在第二部分中,您为每个后代类指定了个人静态存储字段,因此它们不使用基类字段,而是使用自己的字段(它与父字段重叠,因为使用相同的名称)。
简而言之,第一对后代类使用base1::$instance
来检查和创建实例。第二对使用自己的字段sub21::$instance
和sub22::$instance
来执行此任务。
您可以通过放弃 base1 类中的后期静态绑定来阻止这种情况:
class base1
{
/*
* Instance of class
* mixed
*/
protected static $instance = null;
/*
* For Singleton Pattern
*/
public static function instance() {
if ( null == self::$instance ) {
// ^ self instead of static
self::$instance = new static();
// ^ self instead of static
}
return self::$instance;
// ^ self instead of static
}
public function test()
{
$test = "base1";
var_dump($test);
}
}
我确实建议您阅读late static binding以及self
和static
个关键字之间的区别。
<强> UPDv1:强>
如果您仍然只需要获取每个后代类的一个实例,则可以将单例方法更改为:
class base1
{
/*
* Instances of descendant classes
* array
*/
protected static $instances = [];
/*
* For Singleton Pattern
*/
public static function instance() {
if (empty(self::$instances[static::class])) {
$instance = new static();
self::$instances[static::class] = $instance;
} else {
$instance = self::$instances[static::class];
}
return $instance;
}
public function test()
{
$test = "base1";
var_dump($test);
}
}