假设你有这个:
<?php
interface Type
{}
class SomeType implements Type
{}
class SomeOtherType implements Type
{}
现在,如果你有一个抽象类,它具有Type
接口作为构造函数依赖,如下所示:
<?php
abstract class TypeUser
{
public function __construct(Type $type)
{}
}
为什么PHP允许你在具体类上重载构造函数,如下所示:
<?php
class SomeTypeUser extends TypeUser
{
public function __construct(SomeType $type)
{}
}
class SomeOtherTypeUser extends TypeUser
{
public function __construct(SomeOtherType $type)
{}
}
但它不允许你为方法做同样的事情,只有构造函数 - 如果你尝试用非构造函数方法做,那么PHP会抛出Strict standards
错误?
答案 0 :(得分:0)
请阅读:Override method parameter with child interface as a new parameter
TL; DR:如果使用 narrower 类型重载方法参数类型,则会更改方法签名并使其与父方法不兼容。您不能用任意子类替换TypeUser
的实例,因为重载的子类的方法签名与父类不兼容,因此没有给出用于调用此类实例的稳定的已知接口。
为什么它适用于构造函数?因为构造实例,您(通常)硬编码其类名:
$user = new SomeTypeUser($parameter);
这里没有含糊不清的构造函数所期望的参数,你确切知道你要实例化的是什么类。
但是,情况并非如此:
function (TypeUser $user) {
$user->foo($something);
}
那么,$user
是哪一个类的实例? SomeTypeUser
? SomeOtherTypeUser
?完全不同的东西?是$user->foo()
的签名foo(SomeType $type)
还是foo(SomeOtherType $type)
?以上代码是否会在运行时爆炸?谁知道......
答案 1 :(得分:-1)
PHP允许在inherted方法中重载参数,只要它们未定义为abstract
或属于类扩展/实现的interface
。
interface Foo {
public function baz(ArrayObject $array);
}
class Bar implements Foo {
public function baz(DateTime $dateTime) {
}
}
或
abstract class Foo {
public abstract function baz(ArrayObject $array);
}
class Bar extends Foo {
public function baz(DateTime $dateTime) {
}
}
将导致众所周知的错误:
致命错误:Bar :: baz()的声明必须与xy行上的/.../test.php中的Foo :: baz(ArrayObject $ array)兼容
虽然
abstract class Foo {
public function baz(ArrayObject $array) {
}
}
class Bar extends Foo {
public function baz(DateTime $dateTime) {
}
}
很好并且有效,因为baz
方法不是接口定义方法的实现,也不是父类中的抽象方法。