为什么我收到此错误:
Fatal error: Declaration of ConcreteFooMapper::load() must be compatible with that of AbstractFooMapper::load() on line 18
来自此代码:
<?php
interface Foo {
public function foo();
}
class ConcreteFoo implements Foo {
public function foo() {
}
}
abstract class AbstractFooMapper {
abstract public function load(Foo $entity, array $data);
}
class ConcreteFooMapper extends AbstractFooMapper {
public function load(ConcreteFoo $entity, array $data) {
}
}
?>
我最初的想法是,这是一个错误; PHP在评估方法声明时没有检测到 ConcreteFoo 实现 Foo 。我认为这是因为当你运行这段代码时:
<?php
interface Foo {
public function foo();
}
class ConcreteFoo implements Foo {
public function foo() {
}
}
$foo = new ConcreteFoo();
if ($foo instanceof Foo)
{
print 'w00t!';
}
else
{
print 'FAIL!';
}
?>
打印 w00t!表示 ConcreteFoo 是 Foo 的一个实例。
有关此行为是否正确的任何见解?
答案 0 :(得分:3)
根据docs,类型提示必须完全匹配。
答案 1 :(得分:2)
实现接口的类必须使用与接口中定义的完全相同的方法签名。不这样做会导致致命错误。对扩展抽象类的类也有相同的规则。
请参阅see in details here,see here too
这是正确的行为\逻辑。
check here抽象类型非常有用,因为它们可用于定义和实施协议;实现协议的所有对象必须支持的一组操作。
如果我们假设您的代码无异常,那么我们就会遇到以下问题:ConcreteFooMapper
无法使用某些class ConcreteFoo2 implements Foo
的实例作为load
方法的参数,但应该(通过抽象类定义)
此外,如果您使用相同的签名,它确实不是问题,导致所有类\ type信息可用。请检查以下代码
<?php
interface Foo {
public function foo();
}
class ConcreteFoo implements Foo {
public function foo() {
}
}
abstract class AbstractFooMapper {
abstract public function load(Foo $entity, array $data);
}
class ConcreteFooMapper extends AbstractFooMapper {
public function load(Foo $entity, array $data) {
var_dump($entity instanceof Foo);
var_dump($entity instanceof ConcreteFoo);
}
}
$someConcreteFoo = new ConcreteFoo();
$someFooMapper = new ConcreteFooMapper();
$someFooMapper->load($someConcreteFoo, array('somekey' => 'somevalue'));
// output
// bool(true) bool(true)
?>
答案 2 :(得分:0)
有趣的是,您可以使用构造函数来增强谓词:
// ABuilder.php
abstract class ABuilder
{
public function __construct(BaseApi $api = null)
{
$this->api = $api;
}
public static function fromArray(array $data, BaseApi $api = null)
{
$entity = new static($api);
// ...
return $entity;
}
}
// ContactBuilder.php
class Contact extends ABuilder
{
// here, you cannot change signature of ::fromArray to require ContactApi
// (which extends/implements BaseApi), like in this example:
public static function fromArray(array $data, ContactApi $api = null) {}
// but you can specify ContactApi in the constructor arguments:
public function __construct(ContactApi $api = null) {}
}
因此,当您尝试使用错误的Api实现初始化ContactBuilder
类(甚至通过::fromArray()
结构)时,也会收到类似以下内容的正确的Type错误消息:
传递给Builder / Contact :: __ construct()的参数1必须是 ContactApi的实例或为null,指定了LeadApi的实例