本节书摘来自华章出版社《Hack与HHVM权威指南》一书中的第1章,第1.5.2节,作者 Owen Yamauchi,更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1.5.2 覆盖方法的类型
在Hack的代码之间,继承是更加复杂的相互关系中的一种。这复杂性主要来自于当继承关系被创建时,继承和被继承的代码之间的分离现象。举例来说,如果你有个类型标注为SomeClass的对象并可以调用这个对象的某个方法,那么你可以调用继承自SomeClass的任何类的某个方法。这个调用仍然需要是类型安全的,这就意味着覆盖其他方法的时候,方法的类型必须有一定的规则。
在一个覆盖方法中,参数类型必须和被覆盖的方法类型完全一致。这主要是因为继承自PHP的一个行为。在PHP中,任何覆盖自抽象方法或者接口中声明的覆盖方法,都必须精确地匹配被覆盖方法的参数类型。这在未来Hack版本中的声明可能会有所改变,允许改变方法的参数类型将是更通常的做法。
换句话说,当进行方法覆盖时,覆盖方法的返回类型并不一定保持相同,相对于被覆盖的方法而言,覆盖方法可以有一个更加明确的返回类型。例如:
class ParentClass {
public function generate(): num {
// ...
}
}
class ChildClass extends ParentClass {
public function generate(): int { // OK
// ...
}
}
虽然改变了返回类型,这种多态的调用仍然是类型安全的。
function f(ParentClass $obj) {
$number = $obj->generate();
// 即使$obj是个ChildClass实例,generate()方法自然会返回num类型
// 因为ChildClass::generate() 返回的是int类型,而所有int类型都属于num类型
用更通常的返回类型进行覆盖是非法的。例如,如果ChildClass的generate()方法被声明成返回类型为mixed的话,类型检查器将会报告错误。