【问题标题】:PHP Extending class makes children inherit same static propertyPHP扩展类使孩子继承相同的静态属性
【发布时间】:2026-02-22 17:45:01
【问题描述】:

我想先展示一个测试用例:

class A {
    public static $instance=null;
    public function __construct(){
        self::$instance=$this;
    }
    public function className(){
        return get_class(self::$instance);
    }
}

class B extends A {
    public function className(){
        return get_class(self::$instance);
    }
}

// test code
$b=new B();
echo $b->className; // B
$a=new A();
echo $a->className; // A
echo $b->className; // A <- error: not B any more!

备注

  • 我在上面使用工厂+单例模式。嗯,有点。
  • 我不需要任何关于“正确实现模式”的规范。我需要解决问题,而不是违反 KISS ;)。
  • 批评者可能会说 A 应该是一个接口。理想情况下,它应该是这样的,但它只是一个简单的类,抱歉。

问题在于self::$instance 对于所有实例都是相同的。如何为每个班级分隔self::$instance

编辑:我有这个想法:

$GLOBALS['store']=array();
class A {
    public static $instance=null;
    public function __construct(){
        $GLOBALS['store'][__CLASS__]=$this;
    }
}

【问题讨论】:

  • 这就是静态的意思。它们都使用相同的变量。所以任何改变都会改变变量。
  • 我不确定__CLASS__ 是否在运行时确定... IMO 将始终为“A”。
  • 啊,我明白你在做什么。一旦您向明确的问题添加了额外的信息,它就不再是傻瓜了。
  • @giraff: __CLASS__ 在编译时确定...如果要使用后期静态绑定(5.3+),请使用static::$foo 而不是self::$foo...

标签: php static singleton properties factory


【解决方案1】:

您可以为每个类名存储一个实例:

class A { 
    public static function getInstance(){
        // Maybe use this function to implement the singleton pattern ...
        return self::$instance[get_called_class()];
    }

    public function className(){
        return get_class(self::getInstance());
    }   
}

【讨论】:

  • get_called_class() 正是我所需要的,以避免弄乱子类的代码。
【解决方案2】:

你不能以干净的方式做到这一点。 这是 stati 属性的主要缺点之一:您不能覆盖它们。

但是你想要一个解决方案,所以.....这里是 worarround: 使用 __callllStatic

  <?php 
 class A {
    public static function __callstatic($name,$args)
    {
        if($name="getClass"){
                return 'A';
        }
    }
 }

 class  B extends  A{
 public static function __callstatic($name,$args)
    {
        if($name="getClass"){
                return 'B';
        }
    }
 }


echo  A::getClass();
echo  B::getClass();
?>

这个的输出是“AB”;

【讨论】:

    【解决方案3】:

    您可以在 B 类中添加 public static $instance=null; 声明。

    class A {
        public static $instance=null;
        public function __construct(){
            self::$instance=$this;
        }
        public function className(){
            return get_class(self::$instance);
        }
    }
    
    class B extends A {
        public static $instance=null;
        public function className(){
            return get_class(self::$instance);
        }
    }
    
    // test code
    $b=new B();
    echo $b->className(); // B
    $a=new A();
    echo $a->className(); // A
    echo $b->className(); // Now returns B, as desired.
    

    【讨论】:

    • 我知道这一点(应该在帖子中描述)。这样做的问题是 B 类需要有“不必要的代码”来容纳 A 类。虽然可用,但它有点不方便,因为无论如何::$instance 应该是“内部的”。尽管为这个想法+1;清楚地显示 OOP 行为。