从父类中访问子类的静态变量?

15

我有一个基类,需要在子类中引用的另一个类上调用函数。

这很简单,

class base_class {

    public function doSomethingWithReference(){
        $this->reference->doSomething();
    }
}

class extended_class extends base_class{

    protected $reference;

    public function __construct($ref){
        $this->reference = $ref;
    }
}

现在这个显然可以正常工作,

但是,当我调试时,我不关心 $this->reference 的值

但是,$this->reference 引用的对象非常庞大!

所以,当我执行 print_r($instanceOfExtendedClass) 时,会打印出那个对象。

现在每个扩展 base_class 的类的引用都是不同的。

我想做的就是将 reference 设置为 extended_class 类上的静态属性。

但是,将 doSomethingWithReference 更改为 self::$reference 会抛出未定义的变量错误。

而且,将静态变量设置在 base_class 中并从 extended_class 修改它不起作用,因为它将更改所有从该类继承的变量。

有没有办法做到这一点,使我不会得到 $this->reference 的打印输出?


2
你正在使用哪个版本的PHP?在5.3中,static行为发生了一些重大变化,如果你被困在旧版本上,那么你得到的答案将会非常不同。 - Charles
这个类的结构违反了某些规则,我只是不确定是什么 :) - Ja͢ck
2个回答

27
因为您正在使用PHP 5.3,所以可以使用late static binding来在运行时解析对正确类的静态调用。
class base_class {

    public function doSomethingWithReference(){
        static::$reference->doSomething();
    }

}

class extended_class extends base_class{

    protected static $reference;

    public function __construct($ref){
        static::$reference = $ref;
    }

}

重要提醒:extended_class::$reference只有一个实例,将被共享给所有的extended_class实例。如果这不是你想要的结果,那么这不会起作用。

看起来您真正担心的是内存或资源使用情况。在PHP中,所有对象都是传递引用的。这意味着将对象作为参数传递、创建副本等操作不会消耗额外的内存。如果您需要在许多其他对象中引用一个对象,这样做不会消耗额外的内存。


如果我有一个extended_class和另一个完全相同的类(比如extended_class1),它们也会共享引用吗?还是所有extended_class实例都共享一个引用,而所有extended_class1实例将共享另一个引用(理想情况)?

看起来共享是基于静态变量定义的位置。以下是两个例子,都来自PHP交互提示符:

php > class Shared { public $me; public function __construct($me) { $this->me = $me; } }
php > class Base { protected static $ref; public function foo() { echo static::$ref->me, "\n"; } }
php > class Inherit_1 extends Base { public function __construct($ref) { static::$ref = $ref; } }
php > class Inherit_2 extends Base { public function __construct($ref) { static::$ref = $ref; } }
php > class Inherit_3 extends Inherit_1 {}
php > $shared_1 = new Shared(1)
php > ;
php > $shared_2 = new Shared(2);
php > $shared_3 = new Shared(3);
php >
php > $in_1 = new Inherit_1($shared_1);
php > $in_2 = new Inherit_2($shared_2);
php > $in_3 = new Inherit_3($shared_3);
php >
php > $in_1->foo();
3
php > $in_2->foo();
3
php > $in_3->foo();
3

在这种情况下,由于引用位于基类中,每个人都看到相同的引用。我想这有某种道理。

当我们在每个子类中声明引用时,大多数时间会发生什么?

php > class Shared { public $me; public function __construct($me) { $this->me = $me; } }
php > class Base { public function foo() { echo static::$ref->me, "\n"; } }
php > class Inherit_1 extends Base { protected static $ref; public function __construct($ref) { static::$ref = $ref; } }
php > class Inherit_2 extends Base { protected static $ref; public function __construct($ref) { static::$ref = $ref; } }
php > class Inherit_3 extends Inherit_1 {}
php > class Inherit_4 extends Inherit_1 { protected static $ref; }
php > $shared_1 = new Shared(1);
php > $shared_2 = new Shared(2);
php > $shared_3 = new Shared(3);
php > $shared_4 = new Shared(4);
php > $in_1 = new Inherit_1($shared_1);
php > $in_2 = new Inherit_2($shared_2);
php > $in_3 = new Inherit_3($shared_3);
php > $in_4 = new Inherit_4($shared_4);
php > $in_1->foo();
3
php > $in_2->foo();
2
php > $in_3->foo();
3
php > $in_4->foo();
4

因为3从1继承而来,没有声明它自己的静态属性,所以它继承了1的静态属性。当我们将3的静态属性设置为Shared(3)时,它覆盖了1现有的Shared(1)。

结论:为使此方法可行,该属性需要在每个需要单一唯一引用的类中声明。请注意,此代码有效的版本为5.4.x。


我并不真正担心内存问题,这只是为了调试方便。我不喜欢滚动大约600行(Code Igniter对象!)来查看对象属性!你提到的extended_class::$reference共享引用,如果我有一个extended_class和另一个完全相同的类(比如extended_class1),它们也会共享引用吗?还是所有extended_class的实例都共享一个引用,而所有extended_class1的实例则共享另一个引用(理想情况)? - Hailwood
@Hailwood,我已经更新了我的答案,并提供了一个测试,演示了静态属性的解析位置。 - Charles

2

提供一种让父类可以访问子类静态成员的方法:

<?php

abstract class base_class {
    abstract protected function reference();
    // If you want to be able to instanciate base class directly, use the following 2 lines in place of the previous 2 lines:
//class base_class {
    //protected function reference() {}

    public function doSomethingWithReference(){
        $this->reference()->doSomething();
    }
}

class extended_class extends base_class{
    protected static $reference;

    public function __construct($ref){
        self::$reference = $ref;
    }

    protected function reference(){
        return self::$reference;
    }
}

class ref {
    public function doSomething(){
        echo __METHOD__;
    }
}

$ref = new ref();
$ec = new extended_class($ref);
$ec->doSomethingWithReference();

print_r($ec);
?>

2
-1,这只是一堆代码。你没有解释这段代码是什么,为什么它能工作,它是如何工作的,以及它如何回答问题。 - Charles
3
感谢您的批评,@Charles - 没有任何讽刺的意思。实际上,我赞同您的评论。将来,我会确保更加详细地说明问题,不会假设读者可以仅通过阅读代码就理解正在发生的事情。我手头没有 PHP<5.3 的工具箱,但我相信这个例子适用于那些没有使用后期静态绑定功能的用户。一旦我确认它在较早版本中有效,我将更��我的答案以解释其中的原因和方法,并声明该答案对于使用 PHP < 5.3 的用户是有价值的。 - Starson Hochschild

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接