← PHP析构函数:对象销毁时的资源清理机制 PHP中的重载:远不止同名方法那么简单 →

PHP面向对象核心:掌握继承,写出更聪明的代码

原创 2026-05-12 PHP 已有人查阅

在项目里,几乎没人会从头开始写一个功能完备的类。多数时候,我们会发现一个新需求和一个旧类有七八分相似。这时候,如果选择复制粘贴,就是麻烦的开始——一旦公共逻辑需要调整,就得修改多处代码,还很容易遗漏。

PHP面向对象编程里的继承,就是为解决“类与类之间代码复用和差异化”这个实际问题而生的。它让我们能在一个已有类的基础上,通过扩展的方式来构建新类,从而构建出清晰的逻辑层级。

认识 “IS-A” 关系:继承的逻辑基础

在使用继承前,需要先理解一个概念:“IS-A”关系。这不是语法,而是一种逻辑判断,用来验证你的继承设计是否合理。

简单来说,如果可以说“子类是一个父类”,那这个继承关系大概率是成立的。例如,“狗是一个动物”,所以让Dog类去继承Animal类是合乎逻辑的。反过来,如果“汽车有一个引擎”,这就是组合关系,而非继承。个人建议,先用“IS-A”原则检验你的类关系,这能避免很多后续设计中不必要的重构。

PHP里的三种继承模式

PHP自身支持通过 extends 关键字实现的单一继承,但通过巧妙运用,可以形成三种经典的继承模式。

语法结构很简单:

class 子类名 extends 父类名 {
   // 这里子类会继承父类所有 public 和 protected 的成员(属性和方法)
   // 你可以在这里添加新功能,或者重写父类已有的方法
}
1. 单层继承:最直接的应用

单层继承是指一个子类直接从唯一的父类继承而来。这是日常开发里使用频率比较高的模式,因为它能明确地表达一个简单的扩展关系。子类能立刻获得父类的公共和受保护成员,省去了重复声明。

<?php
// 定义一个基础的动物类
class Animal {
    public function makeSound() {
        echo "动物发出声音。\n";
    }
}

// 定义一个狗类,它继承自动物类
class Dog extends Animal {
    // 这是狗类特有的方法
    public function bark() {
        echo "狗在吠叫。\n";
    }
}

// 实例化狗类
$myDog = new Dog();

// 调用从父类Animal继承来的方法
$myDog->makeSound();

// 调用狗类自身定义的方法
$myDog->bark();
?>

这段代码运行后,你会看到,Dog类的对象成功调用了属于Animal的方法,这正是单层继承的核心价值——既复用了Animal的通用功能,又通过Dog类体现了独特性。

2. 多层继承:构建功能传递链

多层继承形成了一条继承链:父类被一个子类继承,这个子类又作为父类,被另一个类继承。这样,链条末端的类就自然具备了其上所有祖先类的能力。

这种模式适合用在功能需要逐级特化的场景。比如一个基础Animal类,到一个更具体的Dog类,再到一个更细分的Puppy类。

<?php
class Animal {
    public function makeSound() {
        echo "动物发出声音。\n";
    }
}

class Dog extends Animal {
    public function bark() {
        echo "狗在吠叫。\n";
    }
}

// Puppy类继承了Dog,也就间接继承了Animal
class Puppy extends Dog {
    public function whimper() {
        echo "小狗在呜咽。\n";
    }
}

$myPuppy = new Puppy();
$myPuppy->makeSound(); // 方法继承自Animal
$myPuppy->bark();      // 方法继承自Dog
$myPuppy->whimper();   // 方法定义在Puppy自身
?>

这里Puppy对象能调用Animal的方法,就是多层继承的直接体现。个人经验是,继承层级不宜过深,通常维持在2-3层,能让代码保持较高的可读性和维护性。

3. 层次化继承:一个父类,多个子类

当多个不同的子类共享同一个父类时,就形成了层次化继承。这个模式的出现,是因为它们都满足“IS-A”关系,且都需要复用父类的公共属性和方法。

典型的例子是,DogCat都是一种Animal。它们都能发出声音,但具体发声方式不同。

<?php
class Animal {
    public function makeSound() {
        echo "动物发出声音。\n";
    }
}

class Dog extends Animal {
    public function bark() {
        echo "狗在吠叫。\n";
    }
}

class Cat extends Animal {
    public function meow() {
        echo "猫在喵喵叫。\n";
    }
}

$myDog = new Dog();
$myDog->makeSound(); // 来自Animal的通用方法
$myDog->bark();      // Dog特有的方法

$myCat = new Cat();
$myCat->makeSound(); // 来自Animal的通用方法
$myCat->meow();      // Cat特有的方法
?>

在这个例子里,DogCatAnimal那里继承了通用的makeSound()行为,同时又各自实现了bark()meow()。这种写法避免了在DogCat类里重复定义makeSound()

PHP方法重写:改变继承来的行为

有时,父类提供的方法并不能满足子类的具体需求。方法重写就是子类用自己的方法实现,去替换从父类继承下来的同名方法。这不是删除父类方法,而是在子类中提供一个定制版本。

<?php
class 基础类 {
    public function 问候() {
        echo "来自基础类的问候。\n";
    }
    public function 致谢() {
        echo "来自基础类的感谢。\n";
    }
}

class 扩展类 extends 基础类 {
    // 重写了父类的 致谢 方法
    public function 致谢() {
        echo "来自扩展类的特别感谢。\n";
    }
}

// 创建父类对象,调用它原本的方法
$baseObj = new 基础类();
$baseObj->问候();
$baseObj->致谢();

// 创建子类对象,调用继承和重写的方法
$childObj = new 扩展类();
$childObj->问候();  // 这个方法仍然从父类继承
$childObj->致谢();  // 这个方法已经被子类重写
?>

从输出结果能看到,子类对象调用致谢()时,执行的是它自己定义的版本。这就是方法重写赋予PHP面向对象编程的灵活性。记住,私有(private)方法是无法被重写的,因为它对子类不可见。

本节课程知识要点

  1. 继承的核心是代码复用与逻辑层次化:它避免代码重复,并建立起清晰的“IS-A”类关系。

  2. PHP使用extends关键字建立单一继承:基于此可以实现单层、多层、层次化三种经典继承模式。

  3. 访问权限限制了继承范围publicprotected成员会被继承,private成员则不会。

  4. 方法重写实现多态行为的基础:子类可以改变从父类继承的方法,以适应自身需求。

  5. 设计前先用“IS-A”判断:养成这个习惯,能构建出更稳固、易维护的类结构。如果想联系我,可以发邮件到 alan@ebingou.cn。

合理使用继承,能让你的PHP代码结构更接近真实世界的逻辑,当项目规模扩大时,这种组织方式的优势会愈发明显。

← PHP析构函数:对象销毁时的资源清理机制 PHP中的重载:远不止同名方法那么简单 →
分享笔记 (共有 篇笔记)
验证码:
微信公众号