为什么PHP traits不具有静态抽象方法?

通过 PHP v5.3中的静态绑定,可以在接口中有效地声明静态方法;在PHP v5.4中具有特征,方法可以是静态还是抽象,但不能同时使用.这似乎是不合逻辑的和不一致的.

特别地,假设一个特征提供所有实现的接口,除了静态方法;除非该特性中声明了该方法,否则静态分析器将在特征内部引用任何引用.但是,在特征中提供具体的实现不再强制执行/使用类来提供自己的实现 – 这是危险的;抽象静态是理想的,但不允许.

这个矛盾的解释是什么?你会如何建议解决这个问题?

interface MyInterface
{
    public static function getSetting();
    public function doSomethingWithSetting();
}

trait MyTrait
{
    public abstract static function getSetting(); // I want this...

    public function doSomethingWithSetting() {
        $setting = static::getSetting(); // ...so that I can do this
        /* ... */
    }
}

class MyClass implements MyInterface
{
    use MyTrait;
    public static function getSetting() { return /* ... */ }
}
TL; DR:您可以在特征上定义抽象静态,但内部认为这是不好的做法,可能会在将来删除它.

没有多少咖啡因,但我会给它一个裂缝.

严格来说,抽象意味着子类必须实现,静态意味着这个特定类的代码.总而言之,抽象静态意味着“子类必须为此特定类实现代码”.完全正交的概念.

但是,PHP 5.3支持静态继承感谢LSB.所以我们实际上打开了这个定义:自己采用以前的静态定义,而static变为“这个特定类或其任何子类的代码”.抽象静态的新定义是“子类必须为此特定类或其任何子类实现代码”.这可能导致一些人在严格意义上认为静态混淆.参见例如bug #53081.

什么使特质如此特别的引出这个警告?那么看看实施通知engine code

if (ptr->flags & ZEND_ACC_STATIC && (!scope || !(scope->ce_flags & ZEND_ACC_INTERFACE))) {
    zend_error(error_type,"Static function %s%s%s() cannot be abstract",scope ? ZSTR_VAL(scope->name) : "",scope ? "::" : "",ptr->fname);
}

代码表示​​允许抽象静态的唯一位置在接口内.特征不是唯一的,它是抽象静态的定义所独有的.为什么?那么我们的定义有一个小小的角落:

sub-class must implement code for this specific class or any of its sub-classes

使用此代码

abstract class Foo {
    abstract public static function get();
}

那个定义意味着我应该能够调用Foo :: get.毕竟Foo是一个类(看到那个关键字“class”),而在严格的定义中,get就是要在这个类Foo中实现的.但是很明显,没有任何意义,因为我们回到了严格静态的正交性.

如果您尝试使用PHP,您可以获得唯一的理由响应:

Cannot call abstract method Foo::get()

所以因为PHP添加静态继承,它必须处理这些角落的情况.这是特征的本质.一些其他语言(C#,Java等)没有这个问题,因为它们采用严格的定义,根本不允许抽象静态.为了摆脱这种情况,简化引擎,我们可能会在将来强制执行这个“仅在接口中的抽象静态”规则.因此,E_STRICT.

我会使用服务代理来解决问题:

I have common method I want to use in several classes. This common method relies on a static method that must be defined externally to the common code.

trait MyTrait
{
    public function doSomethingWithSetting() {
        $service = new MyService($this);
        return $service->doSomethingWithSetting();
    }
}

class MyService
{
    public function __construct(MyInterface $object) {
        $this->object = $object;
    }
    public function doSomethingWithSetting() {
        $setting = $this->object->getSetting();
        return $setting;
    }
}

感觉有点Rube Goldberg.可能会看静态的动机,并考虑重构它们.

相关文章

统一支付是JSAPI/NATIVE/APP各种支付场景下生成支付订单,返...
统一支付是JSAPI/NATIVE/APP各种支付场景下生成支付订单,返...
前言 之前做了微信登录,所以总结一下微信授权登录并获取用户...
FastAdmin是我第一个接触的后台管理系统框架。FastAdmin是一...
之前公司需要一个内部的通讯软件,就叫我做一个。通讯软件嘛...
统一支付是JSAPI/NATIVE/APP各种支付场景下生成支付订单,返...