5

为什么我会收到此错误:

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!表示ConcreteFooFoo的一个实例。

关于这种行为是否正确的任何见解?

4

3 回答 3

5

根据文档,类型提示必须完全匹配。

于 2012-12-14T03:15:58.187 回答
3

实现接口的类必须使用与接口中定义的完全相同的方法签名。不这样做会导致致命错误。以及扩展抽象类的类的相同规则。

在此处查看详细信息也请参见此处

这是正确的行为\逻辑。

在这里检查抽象类型很有用,因为它们可用于定义和执行协议;实现协议的所有对象都必须支持的一组操作。

如果我们假设您的代码将毫无例外地工作,那么我们有以下问题:ConcreteFooMapper不能使用一些实例class ConcreteFoo2 implements Foo作为load方法的参数,但应该(通过抽象类定义)

此外,如果您使用相同的签名,这真的不是问题,因为所有类\类型信息都可用。请检查以下代码

<?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)  

?>
于 2012-12-14T03:50:08.130 回答
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) {}
}

因此,当您尝试ContactBuilder使用错误的 Api 实现(甚至通过::fromArray()结构)初始化您的类时,您将收到正确的 Type 错误消息,例如:

传递给 Builder/Contact::__construct() 的参数 1 必须是 ContactApi 的实例或 null,给定 LeadApi 的实例

于 2020-09-11T07:09:19.913 回答