PHP 7接口,返回类型提示和自我

Gor*_*onM 73 php interface return-type type-hinting php-7

我在PHP 7中使用返回类型提示遇到了一些问题.我的理解是提示: self意味着你打算让一个实现类返回自己.因此我: self在我的界面中使用来表示,但是当我尝试实际实现接口时,我遇到了兼容性错误.

以下是我遇到的问题的简单演示:

interface iFoo
{
    public function bar (string $baz) : self;
}

class Foo implements iFoo
{

    public function bar (string $baz) : self
    {
        echo $baz . PHP_EOL;
        return $this;
    }
}

(new Foo ()) -> bar ("Fred") 
    -> bar ("Wilma") 
    -> bar ("Barney") 
    -> bar ("Betty");
Run Code Online (Sandbox Code Playgroud)

预期的产出是:

弗雷德威尔玛巴尼贝蒂

我实际得到的是:

PHP致命错误:声明Foo :: bar(int $ baz):Foo必须与iFoo :: bar(int $ baz)兼容:第7行的test.php中的iFoo

问题是Foo是iFoo的一个实现,所以据我所知,实现应该与给定的接口完全兼容.我可以通过更改接口或实现类(或两者)来修复此问题,以通过名称而不是使用返回提示接口self,但我的理解是语义上self意味着"返回您刚刚调用方法的类的实例" ".因此,将其更改为接口意味着理论上我可以返回实现接口的任何实例,而我的意图是调用实例将返回的内容.

这是PHP的疏忽还是这是一个刻意的设计决定?如果它是前者有任何机会看到它在PHP 7.1中修复?如果没有,那么正确的返回提示是什么,你的界面希望你返回刚刚调用方法的实例进行链接的正确方法是什么?

use*_*918 84

self不引用实例,它指的是当前类.接口无法指定必须返回相同的实例 - self以您尝试的方式使用只会强制返回的实例属于同一个类.

也就是说,PHP中的返回类型声明必须是不变的,而您尝试的是协变的.

您的使用self相当于:

interface iFoo
{
    public function bar (string $baz) : iFoo;
}

class Foo implements iFoo
{

    public function bar (string $baz) : Foo  {...}
}
Run Code Online (Sandbox Code Playgroud)

这是不允许的.


返回类型声明RFC这样一段话:

继承期间声明的返回类型的强制执行是不变的; 这意味着当子类型重写父方法时,子类的返回类型必须与父类完全匹配,并且不能省略.如果父级未声明返回类型,则允许子级声明一个.

...

此RFC最初提出了协变返回类型,但由于一些问题而被更改为不变量.可以在将来的某个时刻添加协变返回类型.


目前至少你可以做的最好的事情是:

interface iFoo
{
    public function bar (string $baz) : iFoo;
}

class Foo implements iFoo
{

    public function bar (string $baz) : iFoo  {...}
}
Run Code Online (Sandbox Code Playgroud)

  • 保罗删除你在这里删除的评论实际上是有害的,因为(A)它丢失了重要信息,(B)它扰乱了讨论相对于其他评论的流程.我看不出有什么理由需要删除你依赖马克和戈登的评论.事实上,你在整个地方都这样做,它需要停下来.绝对没有充分的理由回到一个为期一年的问题并删除所有评论,完全破坏了讨论的流程.事实上,它是有害的和破坏性的. (19认同)
  • 也就是说,我本来期望返回类型提示`static`可以工作,但它甚至都没有被识别出来 (13认同)
  • @MarkBaker 返回类型 `static` 被添加到 PHP 8 中。 (2认同)

Gab*_*bor 11

它也可以是一个解决方案,你没有在接口中显式定义返回类型,只在PHPDoc中,然后你可以在实现中定义特定的返回类型:

interface iFoo
{
    public function bar (string $baz);
}

class Foo implements iFoo
{
    public function bar (string $baz) : Foo  {...}
}
Run Code Online (Sandbox Code Playgroud)

  • 或者代替 `Foo` 只使用 `self`。 (2认同)

Ale*_*dru 5

PHP 8 将添加“静态返回类型”,这将解决您的问题。

查看此 RFC: https: //wiki.php.net/rfc/static_return_type