为什么PHP特性不能具有静态抽象方法? - php

通过PHP v5.3中的后期静态绑定,可以在接口中有用地声明static方法。在PHP v5.4中具有特征,方法可以是staticabstract,但不能同时使用。这似乎是不合逻辑和前后矛盾的。

特别是,假设有一个接口,除了静态方法外,特征可以为其提供所有实现;除非在特征中声明了该方法,否则静态分析器会在特征内不对其进行任何引用。但是,在特征中提供具体的实现不再迫使实现/使用类提供自己的实现,这很危险; abstract static是理想选择,但不允许使用。

这种矛盾的解释是什么?您将如何建议解决此问题?

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 7开始,you can。在此之前,您可以在abstract static上定义trait,但是内部人员认为这是不好的做法。

严格地,abstract表示必须实现子类,而static表示仅用于此特定类的代码。综上所述,abstract static表示“子类必须仅为此特定类实现代码”。完全正交的概念。

但是...由于LSB,PHP 5.3+支持静态继承。因此,实际上我们稍微打开了该定义:self采用了static的以前定义,而static变成了“该特定类或其任何子类的代码”。 abstract static的新定义是“子类必须为此特定类或其任何子类实现代码”。这可能会使某些严格意义上认为static的人感到困惑。参见例如bug #53081。

是什么使trait如此引人注意呢?好吧,看看实现通知的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);
}

该代码表示​​允许abstract static的唯一位置是interface中。它对于特征不是唯一的,对于abstract static的定义也是唯一的。为什么?好吧,请注意,在我们的定义中有一个轻微的极端情况:

子类必须为此特定类或其任何子类实现代码

使用此代码:

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

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

如果在PHP中进行尝试,则可能会得到唯一的基本原理响应:

无法调用抽象方法Foo :: get()

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

我将使用服务委托来解决问题:

我有几种常用的方法。该通用方法依赖于必须在通用代码外部定义的静态方法。

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;
    }
}

虽然感觉有些鲁布·戈德堡。可能会考虑静力学的动机,并考虑将其重构。

PHP getallheaders替代 - php

我正在尝试从服务器上的apache切换到nginx。唯一的问题是我在PHP脚本中使用的getallheaders()函数,该函数不适用于Nginx。我已经尝试过用户在getallheaders函数上的php站点上提供的注释,但这并不返回所有请求标头。请告诉我如何解决这个问题。我真的想切换到Nginx。 参考方案 您仍然可以使用它,但是您必须像这里一样重新定义…

PHP:从函数返回值并直接回显它? - php

这可能是一个愚蠢的问题,但是……的PHPfunction get_info() { $something = "test"; return $something; } html<div class="test"><?php echo get_info(); ?></div> 有没有办…

php Singleton类实例将在多个会话中保留吗? - php

举一个简单的例子,如果我想计算一个不使用磁盘存储的脚本的命中次数,我可以使用静态类成员来执行此操作吗?用户1:<?php $test = Example::singleton(); $test->visits++; ?> 用户2:<?php $test = Example::singleton(); $test->visits+…

PHP:将字符串拆分为字母和数字部分的最佳方法 - php

我有几个格式的字符串AA11 AAAAAA1111111 AA1111111 分离字符串的字母和数字部分的最佳方法(最有效)? 参考方案 如果它们都是一系列字母,然后是一系列数字,并且没有非字母数字字符,那么sscanf()可能比regexp更有效$example = 'AAA11111'; list($alpha,$numeric) =…

php-casperjs获取内部文本 - php

我正在为casperjs使用php包装器-https://github.com/alwex/php-casperjs我正在网上自动化一些重复的工作,我需要访问一个项目的innerText,但是我尚不清楚如何从casperjs浏览器访问dom。我认为在js中我会var arr = document.querySelector('label.input…