这涉及到几个 OOP 主题。
首先,简单地覆盖父类中声明的方法就像在继承类中重新声明该方法一样简单。
例如:
class Person {
public function greet(string $whom) {
echo "hello $whom!";
}
}
class Tommy extends Person {
public function greet(string $whom = "everyone") {
echo "Howdy $whom! How are you?";
}
}
$a = new Tommy();
$a->greet('World');
// outputs:
// Howdy World! How are you?
如果在覆盖方法上您想重用被覆盖方法的逻辑,只需从扩展类调用父方法::
class Tommy
{
public function greet(string $whom)
{
// now with more emphasis!!!
echo parent::greet(strtoupper($whom)) . "!!!!";
}
}
现在Tommy::greet()
调用Person::greet()
,但在返回之前修改结果。
需要注意的一点是,覆盖方法必须与被覆盖的方法兼容:方法可见性不能比原始方法更具限制性(可以增加可见性),并且所需参数的数量和类型不能冲突与原始声明。
这是可行的,因为参数的类型与原始参数没有冲突,而且我们需要的参数比父级要少:
class Leo extends Person {
public function greet(string $whom = "gorgeous", string $greet = "Whatsup" ) {
echo "$greet $whom. How are you?";
}
}
但事实并非如此,因为还有额外的必需参数。这将不可能透明地切换原始类,因此会抛出一个Warning
:
class BadBob extends Person {
public function greet(string $whom, string $greet ) {
echo "$greet $whom. How are you?";
}
}
此外,您在问题中提到“此方法应由用户覆盖”。如果您需要客户端类来实际实现该方法,您有几个选择:
抽象类和方法
这些方法的实现是空的,扩展类必须实现才有效。在我们将原来的类更改Person
为:
abstract class Person {
public function greet(string $whom) {
echo "hello $whom!";
}
public abstract function hide();
}
- 由于现在该类包含一个抽象方法,因此也需要将其声明为抽象类。
- 现在无法
Person
直接实例化,只能在其他类中扩展。
- 现在我们所有现有的
Person
扩展类都会出错,尝试执行前面的代码会抛出致命错误。
Person
现在扩展的有效类的示例是:
class Archie extends Person {
public function hide() {
echo "Hides behind a bush";
}
}
任何扩展的类都Person
必须声明一个公共hide()
方法。
接口
最后,您提到了接口。接口是实现类必须履行的契约。他们声明了一组没有实现主体的公共方法。
例如:
interface Policeman {
public function arrest(Person $person) : bool;
public function help($what): bool;
}
现在我们可以拥有扩展Person
和实现的类Policeman
:
class Jane extends Person implements Policeman {
public function hide() {
echo "Jane hides in her patrol-car";
}
public function arrest(Person $person): bool{
// implement arrest method
return false;
}
public function shoot($what): bool {
// implements shoot() method
return false;
}
}
重要的是,虽然可以只扩展一个类(PHP 中没有多重继承),但可以实现多个接口,并且必须满足每个接口的要求才能使类有效。