PHP 类型提示与接口和抽象类不相处?
Posted
技术标签:
【中文标题】PHP 类型提示与接口和抽象类不相处?【英文标题】:Php type hinting not getting along with interfaces and abstract classes? 【发布时间】:2011-06-01 19:23:30 【问题描述】:我认为在代码示例中看到问题比首先编写问题要容易得多。这是我的php代码:
<?php
interface AnInterface
public function method();
class AClass implements AnInterface
public function method()
echo __METHOD__;
abstract class AnAbstractClass
abstract public function method( AnInterface $Object );
class ConcreteClass extends AnAbstractClass
public function method( AClass $Object )
$Object->method();
$Object1 = new ConcreteClass();
$Object2 = new AClass();
$Object1->method( $Object2 );
以上代码导致如下错误:
致命错误:ConcreteClass::method() 的声明必须与 AnAbstractClass::method() 的声明兼容
问题是 php 似乎没有将 AnAbstractClass::method 和 ConcreteClass::method 的签名识别为兼容的。难道我做错了什么?谢谢!
【问题讨论】:
请,请养成发布代码生成的错误消息的习惯。发布代码而不发布输出(或错误)是没有用的。 【参考方案1】:php 似乎无法将
AnAbstractClass::method
和ConcreteClass::method
的签名识别为兼容的。
PHP 是正确的,它们不兼容。通过只允许将AClass
(或其子)的实例传递给ConcreteClass::method
,您违反了AnAbstractClass
提供的约定:它的任何子类都必须接受AnInterface
作为其method()
的参数.
如果您的示例有效,并且我有另一个类 BClass
实现 AnInterface
,我们会遇到这样的情况:根据 AnAbstractClass
,method()
应该接受 BClass
的实例,而根据 @987654333 @,不应该。
更改ConcreteClass::method
的签名以匹配AnAbstractClass::method
的签名。
【讨论】:
【参考方案2】:这是一个示例,说明为什么不允许这样做:
<?php
class BClass implements AnInterface
function moo(AnAbstractClass $abstract)
$b = new BClass();
$abstract->method($b);
这将是一个有效的代码,但如果你将 ConcreteClass
传递给 moo,它会失败,因为它的方法 ConcreteClass::method
不允许 BClass
。
这很复杂,但如果你看一个例子就更容易理解。
【讨论】:
【参考方案3】:不计算。我们昨天也有同样的讨论:Can parameter types be specialized in PHP
所有派生类必须以相同的方式实现方法签名。
这是理想情况下在运行时检查的内容。但在 PHP 中,解析器可以。 (作为补偿,PHP 不会在解析时检查私有/受保护的属性访问,而是让它在运行时爆掉。)
如果您想强制执行更严格的类型,我建议:
assert( is_a($Object, "AClass") );
【讨论】:
鉴于它是 PHP 5,该断言应为assert($Object instanceof AClass);
是的,这可能行得通,但实际上它不是应该的方式,我想我首先有一个误解,请参阅@meagar 的答案
从 ArrayObject 继承之类的情况将 ISTM 非常适合进行类型断言或在收到错误类型时抛出。但是您不能更改基本接口(例如 ArrayAccess::offsetSet 总是会为值采用混合参数)。以上是关于PHP 类型提示与接口和抽象类不相处?的主要内容,如果未能解决你的问题,请参考以下文章