参数类型可以专门用于PHP

时间:2010-12-29 12:09:33

标签: php parameters types

假设我们有以下两个类:

abstract class Foo {
    public abstract function run(TypeA $object);
}

class Bar extends Foo {
    public function run(TypeB $object) {
        // Some code here
    }
}

类TypeB扩展了TypeA类。

尝试使用它会产生以下错误消息:

Bar :: run()的声明必须与Foo :: run()的声明兼容

在涉及参数类型时,PHP真的会被破坏,还是我在这里忽略了这一点?

6 个答案:

答案 0 :(得分:6)

您描述的行为称为covariance,PHP中根本不支持。我不知道内部,但我可能会怀疑PHP的核心在应用所谓的“类型提示”检查时根本不评估继承树。

顺便说一下,PHP也不支持contravariance这些类型提示(一种通常支持其他OOP语言的功能) - 最有可能的原因是上面提到的。所以这也不起作用:

abstract class Foo {
    public abstract function run(TypeB $object);
}

class Bar extends Foo {
    public function run(TypeA $object) {
        // Some code here
    }
}

最后还有一些信息:http://www.php.net/~derick/meeting-notes.html#implement-inheritance-rules-for-type-hints

答案 1 :(得分:2)

这似乎与大多数OO校长非常一致。 PHP与.Net不同 - 它不允许您覆盖类成员。 Foo的任何扩展都应该滑入之前使用Foo的位置,这意味着您无法放松约束。

简单的解决方案显然是删除类型约束,但如果Bar::run()需要不同的参数类型,那么它实际上是一个不同的函数,理想情况下应该有不同的名称。

如果TypeATypeB有任何共同点,请将公共元素移动到基类并将其用作参数约束。

答案 2 :(得分:0)

我认为这是by design:定义其方法的基本行为是抽象定义的重点。

  

从抽象类继承时,父类声明中标记为abstract的所有方法都必须由子类定义;此外,必须使用相同(或限制较少)的可见性来定义这些方法。

答案 3 :(得分:0)

总是可以在代码中添加约束:

public function run(TypeA $object) {
    assert( is_a($object, "TypeB") );

您必须记住或记录特定的类型限制。优点是它变成纯粹的开发工具,因为断言通常在生产服务器上关闭。 (实际上,这是在开发过程中发现的一类错误之一,而不是随机破坏生产。)

答案 4 :(得分:0)

问题中显示的代码无法在PHP中编译。如果确实这样做,则类Bar将无法兑现其父级Foo所作的保证,即不能接受TypeA的任何实例,并且违反了Liskov Substitution Principle

当前相反的代码也不会编译,但是在预期于2019年11月28日发布的PHP 7.4版本中,下面的类似代码将使用新的contravariant arguments功能有效:

abstract class Foo {
    public abstract function run(TypeB $object); // TypeB extends TypeA
}

class Bar extends Foo {
    public function run(TypeA $object) {
        // Some code here
    }
}

所有条形图都为Foos,但并非所有的条形图都为Bars。所有的TypeB都是TypeA,但并非所有的TypeA都是TypeB。任何Foo都可以接受任何TypeB。那些也是Bar的Foos也将能够接受非TypeB TypeA。

PHP也将支持协变返回类型,其工作方式相反。

答案 5 :(得分:-1)

虽然您不能将整个类层次结构用作类型提示。您可以使用selfparent关键字在某些情况下强制执行类似的操作。

引用PHP-manual评论中的r dot wilczek at web-appz dot de

<?php
interface Foo 
{
    public function baz(self $object);
}

class Bar implements Foo
{
    public function baz(self $object)
    {
        // 
    }
}
?>

现在没有提到的是你也可以使用'parent'作为typehint。带接口的示例:

<?php
interface Foo 
{
    public function baz(parent $object); 
}

class Baz {}
class Bar extends Baz implements Foo
{
    public function baz(parent $object)
    {
        // 
    }
}
?>

Bar :: baz()现在将接受任何Baz实例。 如果Bar不是任何类的继承人(没有“扩展”),PHP将引发致命错误: '当前类范围没有父级时,无法访问父::。