UPDATE:PHP7.4Now 是否支持协方差和反向方差?,它解决了在这个问题中提出的主要问题。
在使用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行的iFoo::bar(int $baz):iFoo兼容
问题是Foo是iFoo的一个实现,因此据我所知,实现应该与给定的接口完全兼容。我可以通过更改接口或实现类(或两者)来返回提示接口,而不是使用self来解决这个问题,但我的理解是,在语义上self意味着“返回您刚才调用的方法上的类的实例”。因此,将其更改为接口在理论上意味着,当我的意图是调用实例时,我可以返回实现该接口的任何实例。
这是PHP中的疏忽,还是精心设计的决定?如果是前者,是否有可能在PHP7.1中看到它的修复?如果不是,那么正确的返回方式是什么,暗示您的接口希望您返回刚才调用的用于链接的方法的实例?
发布于 2016-08-22 02:04:28
编辑注意:下面的答案已经过时了。作为php PHP7.4.0,以下内容是完全合法的:
<?php
Interface I{
public static function init(?string $url): self;
}
class C implements I{
public static function init(?string $url): self{
return new self();
}
}
$o = C::init("foo");
var_dump($o);原来的答案:
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 {...}
}发布于 2016-12-20 09:36:03
它也可以是一种解决方案,即在接口中不显式定义返回类型,只在PHPDoc中定义返回类型,然后在实现中定义特定的返回类型:
interface iFoo
{
public function bar (string $baz);
}
class Foo implements iFoo
{
public function bar (string $baz) : Foo {...}
}发布于 2020-08-27 08:43:31
PHP 8将添加“静态返回类型”,这将解决问题。
查看这个RFC:类型
https://stackoverflow.com/questions/39068983
复制相似问题