PHP:类方法参数的类型声明


PHP: Type declaration of class method arguments

当我尝试运行以下代码时,我得到了E_COMPILE_ERROR

<?php
interface DataInterface
{
    public function get();
}
interface ServiceInterface
{
    public function save(DataInterface $data);
}
class Data implements DataInterface
{
    public function get()
    {
        return 'data';
    }
}
class Service implements ServiceInterface
{
    public function save(Data $data)
    {//the problem is here^^
        var_dump($data->get());
    }   
}
$service = new Service();
$data = new Data();
$service->save($data);

Data类是DataInterface接口的实现。我想知道为什么这个代码不能编译?文档指出,有效类型必须是给定类或接口名称的实例。(http://php.net/manual/en/functions.arguments.php#functions.arguments.type-声明)。

$data = new Data();
var_dump($data instanceof DataInterface); //true;

据我所知,如果方法参数的声明类型是实现预期接口的类,那么该类型满足需求(实现所有方法),签名应该匹配。

实现ServiceInterface需要Service
ServiceInterface指定save必须接受DataInterface
Service::save接受Data而不是DataInterface。这不是同一类型,实现与接口声明不兼容。

当您调用Service::save时,重要的是$datainstanceof DataInterface;而不是在声明方法签名时。


为了更深入地了解这一点:接口是这样使用的:

function foo(ServiceInterface $service) {
   $service->save($something);
}

换句话说,某些其他代码将接收implements ServiceInterface。它不知道或不关心$service是什么,只要它实现了ServiceInterface中指定的已知契约。并且ServiceInterface指定可以将任何DataInterface传递给$service::save()而不是Data实例。CCD_ 22可以是CCD_。让Service::save只接受Data实例会破坏该约定并导致运行时错误。

运行代码时出现以下异常:

PHP Fatal error:  Declaration of Service::save() must be compatible with ServiceInterface::save(DataInterface $data) in test.php on line 22
PHP Stack trace:
PHP   1. {main}() test.php:0
Fatal error: Declaration of Service::save() must be compatible with ServiceInterface::save(DataInterface $data) in test.php on line 22
Call Stack:
    0.0002     130808   1. {main}() test.php:0

这个异常非常清楚地说明了您的问题:Service::save()的声明是错误的。它试图接收Date,而它试图覆盖的函数(ServiceInterface::save)接收DateInterface

您应该更改Service::save()的签名以接受DateInterface。您仍然可以将Date对象传递给它,但不能强制它为Date对象。如果你想要一个只接受Date对象(及其子类)的方法,你需要给它一个新的名称。