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::methodConcreteClass::method 的签名识别为兼容的。

PHP 是正确的,它们兼容。通过只允许将AClass(或其子)的实例传递给ConcreteClass::method,您违反了AnAbstractClass 提供的约定:它的任何子类都必须接受AnInterface 作为其method() 的参数.

如果您的示例有效,并且我有另一个类 BClass 实现 AnInterface,我们会遇到这样的情况:根据 AnAbstractClassmethod() 应该接受 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 类型提示与接口和抽象类不相处?的主要内容,如果未能解决你的问题,请参考以下文章

十接口(接口的概念,实现,继承,实现)抽象类与抽象方法(抽象类,抽象方法概念,使用)

9.接口与内部类

抽象类和接口

接口和抽象类的相同与区别

接口和抽象类的相同与区别

抽象类和接口的区别与联系