PHP7接口,返回类型提示和self
更新:PHP 7.4现在解决了这个问题中提出的主要问题PHP7接口,返回类型提示和self,php,interface,return-type,php-7,type-hinting,Php,Interface,Return Type,Php 7,Type Hinting,更新:PHP 7.4现在解决了这个问题中提出的主要问题 我在PHP7中使用返回类型暗示时遇到了一些问题。我的理解是暗示:self意味着您希望实现类返回自身。因此,我在接口中使用了:self来表示这一点,但当我试图实际实现接口时,我得到了兼容性错误 以下是我遇到的问题的简单演示: interface iFoo { public function bar (string $baz) : self; } class Foo implements iFoo { public fun
我在PHP7中使用返回类型暗示时遇到了一些问题。我的理解是暗示
: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");
预期产出为:
弗雷德
威尔玛
巴尼
贝蒂
我实际上得到的是:
PHP致命错误:声明Foo::bar(int$baz):Foo必须与第7行test.PHP中的iFoo::bar(int$baz):iFoo兼容
问题是,Foo是iFoo的一个实现,所以据我所知,这个实现应该与给定的接口完全兼容。我可以通过更改接口或实现类(或两者)来修复此问题,以按名称返回接口提示,而不是使用self
,但我的理解是,从语义上讲self
意味着“返回您刚才调用方法的类的实例”。因此,从理论上讲,将其更改为接口意味着我可以返回实现该接口的任何对象的实例,而我的意图是调用的实例将被返回
这是PHP中的一个疏忽还是一个深思熟虑的设计决策?如果是前者,有没有可能在PHP7.1中看到它被修复?如果不是,那么什么是正确的返回方式,暗示您的接口希望您返回刚刚调用链接方法的实例
self
不引用实例,它引用当前类。接口无法指定必须返回相同的实例-以您尝试的方式使用self
只会强制返回的实例属于同一类
也就是说,PHP中的返回类型声明必须是不变的,而您尝试的是协变的
您使用self
相当于:
interface iFoo
{
public function bar (string $baz) : iFoo;
}
class Foo implements iFoo
{
public function bar (string $baz) : Foo {...}
}
这是不允许的
政府有: 继承期间声明的返回类型的强制是不变的;这意味着,当子类型重写父方法时,子类型的返回类型必须与父类型完全匹配,并且不能忽略。如果父级未声明返回类型,则允许子级声明返回类型 该RFC最初提出了协变返回类型,但由于一些问题而改为不变。可以在将来的某个时候添加协变回报类型
至少目前你能做的最好的事情是:
interface iFoo
{
public function bar (string $baz) : iFoo;
}
class Foo implements iFoo
{
public function bar (string $baz) : iFoo {...}
}
这看起来像是我所期望的行为 只需将您的
Foo::bar
方法更改为返回iFoo
,而不是self
,就可以了
说明:
界面中使用的self
表示“类型为iFoo
的对象”实现中使用的
self
表示“类型为Foo
的对象”
因此,接口和实现中的返回类型显然不同
其中一条评论提到了Java以及您是否会遇到这个问题。答案是肯定的,如果Java允许您编写这样的代码,您也会遇到同样的问题,而Java却不允许。因为Java要求您使用类型的名称而不是PHP的
self
快捷方式,所以您永远不会真正看到这一点。(有关Java中类似问题的讨论,请参阅。)这也可以是一种解决方案,您不需要在接口中明确定义返回类型,只需要在PHPDoc中定义,然后您可以在实现中定义特定的返回类型:
interface iFoo
{
public function bar (string $baz);
}
class Foo implements iFoo
{
public function bar (string $baz) : Foo {...}
}
在这种情况下,当您想从接口强制时,该方法将返回object,但object的类型不是接口的类型,而是类本身,然后您可以这样编写:
interface iFoo {
public function bar(string $baz): object;
}
class Foo implements iFoo {
public function bar(string $baz): self {...}
}
它从PHP7.4开始工作。PHP8将添加“静态返回类型”,这将解决您的问题
查看此RFC:我认为这是PHP返回类型暗示中的一个错误,也许您应该将其作为一个提示来提出;但是任何补丁都不太可能在这么晚的阶段进入PHP7.1。由于7.1的最后一个测试版几天前已经上线,任何补丁都不太可能出于兴趣而进入7.1.0,你在哪里阅读你对
self
返回类型应该如何工作的解释?@Adam:self
的意思似乎是“返回你调用的实例,而不是实现相同接口的其他实例”。我似乎记得Java有一个类似的返回类型(尽管我已经有一段时间没有做任何Java编程了)Hi Gordon。除非有文件证明它在某个地方起作用,否则我不会指望什么是合乎逻辑的现实。对于我要描述的情况,我会尽可能声明性地使用iFoo作为返回类型。有没有一种情况下,这实际上是行不通的?(我意识到这是“建议/意见”,而不是“答案”声明self
,类似于声明MyClass::class
?@Laser是的。但是如果Foo实现了iFoo,那么Foo是根据类型iFoo的定义,也就是说,我本来希望static
的返回类型提示起作用,但它甚至没有被识别出来。我想,情况就是这样,我就是这样做的我将要解决这个问题。但是,如果可能的话,我宁愿只使用:self,因为如果一个类正在实现一个接口,那么self的返回值隐式地也是接口实例的返回值。Paul,删除你在这里删除的注释实际上是有害的,因为(a)它会丢失import