PHP 闭包函数内类的静态成员继承问题

由于最近在开发 WordPress 的开发模板,涉及到一个快速定义自定义文章类型的类(这是题外话),但是遇到这样一个情况:

第一层:从基类方法里面调用子类的静态成员值

假设我们定义一个基类,然后在基类里面定义了一个静态成员属性,并且基类有一个方法调用这些成员属性:

class Base {
    static $static_var = 'base_static';
    public static function static_init() {

        // HERE, I want to get the caller extended class.
        echo __CLASS__.'<br/>';
        // HERE, I want to get the caller extended static variable.
        echo static::$static_var.'<br/>';
        // Do some initialization works depends on the static_var.
        // ...
    }
};

然后,我们对这个基类进行派生,在子类里面会覆盖这个静态成员属性,但不覆盖基类的静态方法,然后我们从子类调用基类的静态方法:

class Children extends Base {
    // overridden
    static $static_var = 'extended_static';
};

这个时候,我们通过子类来调用基类定义的静态方法,这个时候我们希望这个方法调用的静态成员,应当是子类的静态成员值,即被覆盖的值,这样的情况下我们还是可以获取到 static 成员的值的:

// Call Now
Children::static_init();

/** echos:
Base
extended_static
*/

/** I want to export:
Children
extended_static
*/

第二层:加入闭包之后

现在问题是,我在这个基类里面调用了外部的钩子函数,这样在 static 的调用处形成了一个闭包,这个时候 static 的作用域失灵了!

假设我们是这样改动了 Base 基类:

function hook_function($func) {
    $func();
};

class Base {
    static $static_var = 'base_static';
    public static function static_init() {
        hook_function(function() {
            // HERE, I want to get the caller extended class.
            echo __CLASS__.'<br/>';
            // HERE, I want to get the caller extended static variable.
            echo static::$static_var.'<br/>';
            // Do some initialization works depends on the static_var.
            // ...
        });
    }
};

// Call Now
Children::static_init();

/** echos:
Base
base_static
*/

可以看到,这个时候,挂掉了。

第三层:闭包的传递

最后发发现,元凶其实不在类的继承,而是在闭包内。

那么我们如何才能保证在这个闭包函数内部调用到合适的类静态成员?

首先,我们在 static_init 里面,hook_function 之前,static 关键字的指向还是子类的,但是在 hook_function 里面,static 关键字指向了基类!

于是我们需要向闭包函数里面传入子类的类名。

首先,我们可以通过 get_called_class() 来获取类名,这个需要在 hook_function 之前存下来,存到 $class 里面去,然后我们将这个 $class 变量通过闭包参数传到 hook_function 内部:

http://stackoverflow.com/q/31298365/2544762

function hook_function($func) {
    $func();
};

class Base {
    static $static_var = 'base_static';
    public static function static_init() {
        $class = get_called_class();
        hook_function(function() use ($class) {
            // HERE, I want to get the caller extended class.
            echo $class.'<br/>';
            // HERE, I want to get the caller extended static variable.
            echo $class::$static_var.'<br/>';
            // Do some initialization works depends on the static_var.
            // ...
        });
    }
};

class Children extends Base {
    // overridden
    static $static_var = 'extended_static';
};

// Call Now
Children::static_init();

/** echos:
Children
extended_static
*/

大功告成!注意我们在 hook_function 里面定义这个匿名闭包函数的时候使用了 use 关键字并传入了 $class 类名,这个时候在内部就可以通过 $class 类名获取到正确的入口调用子类了!


【转载请附】愿以此功德,回向 >>

原文链接:https://www.huangwenchao.com.cn/2015/07/php-static-closure.html【PHP 闭包函数内类的静态成员继承问题】

发表评论

电子邮件地址不会被公开。 必填项已用*标注