参数类型可以在PHP中专用吗

参数类型可以在PHP中专用吗,php,parameters,types,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()的声明兼容

假设我们有以下两个类:

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真的有这样的缺陷吗?或者我只是错过了这里的要点吗?

我认为这是:定义其方法的基本行为是抽象定义的要点

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


这似乎与大多数OO原则非常一致。PHP不像.Net,它不允许重写类成员。
Foo
的任何扩展都应该滑入先前使用的
Foo
位置,这意味着您不能放松约束

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

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


这个答案已经过时了。


您描述的行为被调用,PHP不支持。我不知道内部结构,但我可能怀疑PHP的核心在应用所谓的“类型提示”检查时根本没有计算继承树

顺便说一句,PHP也不支持这些类型提示(其他OOP语言通常支持这一特性)——最有可能的原因是上面怀疑的。所以这也不起作用:

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

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

最后还有一些信息:

我们可以在代码中添加约束:

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

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

尽管不能使用整个类层次结构作为类型暗示。您可以使用
self
parent
关键字在某些情况下强制执行类似的操作

引用PHP手册注释:

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

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

现在还没有提到的是,您也可以使用“parent”作为类型提示。带有接口的示例:

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

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

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

问题中显示的代码不会在PHP中编译。如果它这样做了,则class
Bar
将无法履行其母公司
Foo
所作的保证,即能够接受
TypeA
的任何实例,并违反了本协议

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

所有的酒吧都是酒吧,但不是所有的酒吧都是酒吧。所有类型都是类型,但并非所有类型都是类型。任何Foo都可以接受任何TypeB。那些同样是条的foo也可以接受非TypeB类型


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

您确定
Foo
不是一个接口,
run()
不是
final
?好的,Pekka。这是一种抽象的方法。我会更正:)当然,但这与方法可见性有关,而不是参数类型。@Johan:你为什么认为这与方法可见性有关?@Stefan他可能指的是我引用的块,它不能解决当前的问题。不过@Johan,基本原则是有效的OOP,而不是bug。没错,Pekka。我指的是引用的文本,而不是PHP手册中提到的文章。扩展一个类型不是专门化了它,从而收紧了约束而不是放松了约束吗?是的。我建议使用基类作为arg类型,这样它的所有子类(TypeA和TypeB)都将符合。当然,假设在你的设置中这是可能的。谢谢Stefan。我知道这适用于大多数其他OO语言,如Java、.NET、SmallTalk等。我想我必须放松一下我的设计,然后转向反射以确保安全。我之前的陈述似乎有点仓促。Java参数实际上是不变的,但会给人一种协变的印象,因为Java支持方法重载
abstract class Foo {
    public abstract function run(TypeB $object); // TypeB extends TypeA
}

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