当我尝试运行以下代码时,我得到了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
时,重要的是$data
是instanceof 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
对象(及其子类)的方法,你需要给它一个新的名称。