继承
什么是继承
继承(Inheritance)是面向对象编程的四大特性之一,它允许一个类(子类)获得另一个类(父类)的属性和方法。通过继承,子类可以重用父类的代码,并在此基础上添加新的功能或修改现有功能。
继承的基本概念
- 父类(Base Class/Super Class):被继承的类,也叫基类
- 子类(Derived Class/Child Class):继承父类的类,也叫派生类
- extends关键字:用于实现继承
- IS-A关系:子类是父类的一种特殊类型
继承的基本语法
<?php
// 定义父类
class Animal {
// 属性
public $name;
public $age;
// 构造函数
public function __construct($name, $age) {
$this->name = $name;
$this->age = $age;
}
// 方法
public function eat() {
echo "{$this->name} 正在吃东西\n";
}
public function sleep() {
echo "{$this->name} 正在睡觉\n";
}
public function getInfo() {
return "这是一只{$this->age}岁的{$this->name}";
}
}
// 定义子类
class Dog extends Animal {
// 子类特有的属性
public $breed;
// 子类构造函数
public function __construct($name, $age, $breed) {
// 调用父类构造函数
parent::__construct($name, $age);
$this->breed = $breed;
}
// 子类特有的方法
public function bark() {
echo "{$this->name} 正在汪汪叫\n";
}
// 重写父类方法
public function getInfo() {
return "这是一只{$this->breed},名字叫{$this->name},今年{$this->age}岁";
}
}
// 使用示例
$dog = new Dog("旺财", 3, "金毛");
// 调用继承的方法
$dog->eat(); // 输出:旺财 正在吃东西
$dog->sleep(); // 输出:旺财 正在睡觉
// 调用子类特有的方法
$dog->bark(); // 输出:旺财 正在汪汪叫
// 调用重写后的方法
echo $dog->getInfo(); // 输出:这是一只金毛,名字叫旺财,今年3岁
?>
parent关键字
parent关键字用于访问父类的属性和方法。
调用父类构造函数
<?php
class Vehicle {
protected $brand;
protected $model;
public function __construct($brand, $model) {
$this->brand = $brand;
$this->model = $model;
echo "车辆构造函数被调用\n";
}
public function start() {
echo "启动 {$this->brand} {$this->model}\n";
}
}
class Car extends Vehicle {
private $doors;
public function __construct($brand, $model, $doors) {
// 调用父类构造函数
parent::__construct($brand, $model);
$this->doors = $doors;
echo "汽车构造函数被调用\n";
}
public function openDoors() {
echo "打开{$this->doors}扇车门\n";
}
// 重写父类方法
public function start() {
// 调用父类方法
parent::start();
echo "汽车启动,准备出发!\n";
}
}
$car = new Car("丰田", "卡罗拉", 4);
// 输出:
// 车辆构造函数被调用
// 汽车构造函数被调用
$car->start();
// 输出:
// 启动 丰田 卡罗拉
// 汽车启动,准备出发!
?>
访问控制与继承
访问修饰符在继承中的表现:
<?php
class Person {
public $publicVar = "公开属性"; // 公开的,子类可以直接访问
protected $protectedVar = "受保护属性"; // 受保护的,子类可以访问
private $privateVar = "私有属性"; // 私有的,子类不能直接访问
public function showVars() {
echo "公开属性:{$this->publicVar}\n";
echo "受保护属性:{$this->protectedVar}\n";
echo "私有属性:{$this->privateVar}\n";
}
protected function protectedMethod() {
echo "这是父类的受保护方法\n";
}
private function privateMethod() {
echo "这是父类的私有方法\n";
}
}
class Student extends Person {
public function accessParentVars() {
echo "访问父类的公开属性:{$this->publicVar}\n"; // ✅ 可以访问
echo "访问父类的受保护属性:{$this->protectedVar}\n"; // ✅ 可以访问
// echo "访问父类的私有属性:{$this->privateVar}\n"; // ❌ 不能访问
}
public function accessParentMethods() {
$this->protectedMethod(); // ✅ 可以调用
// $this->privateMethod(); // ❌ 不能调用
}
public function showAllVars() {
// 可以通过父类的公开方法间接访问私有属性
$this->showVars();
}
}
$student = new Student();
$student->accessParentVars();
$student->accessParentMethods();
$student->showAllVars();
// 直接访问
echo $student->publicVar; // ✅ 可以访问
// echo $student->protectedVar; // ❌ 不能访问
// echo $student->privateVar; // ❌ 不能访问
?>
方法重写(Method Overriding)
子类可以重新定义父类的方法,这称为方法重写。
基本重写
<?php
class Shape {
protected $name;
public function __construct($name) {
$this->name = $name;
}
public function draw() {
echo "绘制一个{$this->name}\n";
}
public function getArea() {
echo "计算{$this->name}的面积\n";
return 0;
}
}
class Circle extends Shape {
private $radius;
public function __construct($radius) {
parent::__construct("圆形");
$this->radius = $radius;
}
// 重写draw方法
public function draw() {
echo "绘制一个半径为{$this->radius}的圆形\n";
}
// 重写getArea方法
public function getArea() {
$area = pi() * $this->radius * $this->radius;
echo "圆形面积:{$area}\n";
return $area;
}
}
class Rectangle extends Shape {
private $width;
private $height;
public function __construct($width, $height) {
parent::__construct("矩形");
$this->width = $width;
$this->height = $height;
}
// 重写draw方法
public function draw() {
echo "绘制一个{$this->width}x{$this->height}的矩形\n";
}
// 重写getArea方法
public function getArea() {
$area = $this->width * $this->height;
echo "矩形面积:{$area}\n";
return $area;
}
}
$circle = new Circle(5);
$circle->draw(); // 输出:绘制一个半径为5的圆形
$circle->getArea(); // 输出:圆形面积:78.539816339745
$rectangle = new Rectangle(4, 6);
$rectangle->draw(); // 输出:绘制一个4x6的矩形
$rectangle->getArea(); // 输出:矩形面积:24
?>
使用final关键字防止重写
<?php
class Calculator {
// final方法不能被重写
final public function add($a, $b) {
return $a + $b;
}
public function subtract($a, $b) {
return $a - $b;
}
}
class AdvancedCalculator extends Calculator {
// ✅ 可以重写普通方法
public function subtract($a, $b) {
return abs($a - $b); // 返回绝对值
}
// ❌ 不能重写final方法
// public function add($a, $b) {
// return $a + $b + 1;
// }
public function multiply($a, $b) {
return $a * $b;
}
}
// final类不能被继承
final class MathUtils {
public static function factorial($n) {
if ($n <= 1) return 1;
return $n * self::factorial($n - 1);
}
}
// ❌ 不能继承final类
// class MyMath extends MathUtils {
// }
?>
多层继承
<?php
// 祖父类
class LivingBeing {
protected $name;
public function __construct($name) {
$this->name = $name;
}
public function breathe() {
echo "{$this->name} 正在呼吸\n";
}
}
// 父类
class Animal extends LivingBeing {
protected $species;
public function __construct($name, $species) {
parent::__construct($name);
$this->species = $species;
}
public function move() {
echo "{$this->name} 正在移动\n";
}
public function eat() {
echo "{$this->name} 正在吃东西\n";
}
}
// 子类
class Mammal extends Animal {
protected $furColor;
public function __construct($name, $species, $furColor) {
parent::__construct($name, $species);
$this->furColor = $furColor;
}
public function produceMilk() {
echo "{$this->name} 正在产奶\n";
}
public function showInfo() {
echo "种类:{$this->species}\n";
echo "毛色:{$this->furColor}\n";
}
}
// 孙子类
class Dog extends Mammal {
private $breed;
public function __construct($name, $breed, $furColor) {
parent::__construct($name, "哺乳动物", $furColor);
$this->breed = $breed;
}
public function bark() {
echo "{$this->name} 正在汪汪叫\n";
}
public function showAllInfo() {
echo "名字:{$this->name}\n";
echo "品种:{$this->breed}\n";
$this->showInfo();
}
}
// 使用示例
$dog = new Dog("小白", "贵宾犬", "白色");
$dog->breathe(); // 祖父类的方法
$dog->move(); // 父类的方法
$dog->eat(); // 父类的方法
$dog->produceMilk(); // 父类的方法
$dog->bark(); // 子类自己的方法
$dog->showAllInfo();
// 输出:
// 名字:小白
// 品种:贵宾犬
// 种类:哺乳动物
// 毛色:白色
?>
继承的实际应用:员工管理系统
<?php
// 基础员工类
class Employee {
protected $id;
protected $name;
protected $baseSalary;
public function __construct($id, $name, $baseSalary) {
$this->id = $id;
$this->name = $name;
$this->baseSalary = $baseSalary;
}
// 计算工资(基础方法)
public function calculateSalary() {
return $this->baseSalary;
}
// 获取员工信息
public function getEmployeeInfo() {
return [
'id' => $this->id,
'name' => $this->name,
'type' => '普通员工',
'salary' => $this->calculateSalary()
];
}
// 工作方法
public function work() {
echo "{$this->name} 正在工作\n";
}
}
// 经理类
class Manager extends Employee {
private $bonus;
private $department;
public function __construct($id, $name, $baseSalary, $bonus, $department) {
parent::__construct($id, $name, $baseSalary);
$this->bonus = $bonus;
$this->department = $department;
}
// 重写计算工资方法
public function calculateSalary() {
return $this->baseSalary + $this->bonus;
}
// 重写员工信息方法
public function getEmployeeInfo() {
$info = parent::getEmployeeInfo();
$info['type'] = '经理';
$info['department'] = $this->department;
return $info;
}
// 经理特有方法
public function manageTeam() {
echo "{$this->name} 正在管理{$this->department}部门\n";
}
public function approveRequest($request) {
echo "经理{$this->name}批准了请求:{$request}\n";
}
public function work() {
parent::work();
echo "{$this->name} 正在制定部门计划\n";
}
}
// 销售员类
class Salesperson extends Employee {
private $commissionRate;
private $salesAmount;
public function __construct($id, $name, $baseSalary, $commissionRate) {
parent::__construct($id, $name, $baseSalary);
$this->commissionRate = $commissionRate;
$this->salesAmount = 0;
}
// 重写计算工资方法
public function calculateSalary() {
$commission = $this->salesAmount * $this->commissionRate;
return $this->baseSalary + $commission;
}
// 重写员工信息方法
public function getEmployeeInfo() {
$info = parent::getEmployeeInfo();
$info['type'] = '销售员';
$info['sales_amount'] = $this->salesAmount;
$info['commission'] = $this->salesAmount * $this->commissionRate;
return $info;
}
// 销售特有方法
public function makeSale($amount) {
$this->salesAmount += $amount;
echo "{$this->name} 完成了 {$amount} 元的销售额\n";
}
public function work() {
parent::work();
echo "{$this->name} 正在联系客户\n";
}
}
// 技术员类
class Technician extends Employee {
private $skillLevel;
private $overtimeHours;
public function __construct($id, $name, $baseSalary, $skillLevel) {
parent::__construct($id, $name, $baseSalary);
$this->skillLevel = $skillLevel;
$this->overtimeHours = 0;
}
// 重写计算工资方法
public function calculateSalary() {
$overtimePay = $this->overtimeHours * 100; // 每小时加班费100元
$skillBonus = $this->skillLevel * 500; // 技能等级奖励
return $this->baseSalary + $overtimePay + $skillBonus;
}
// 重写员工信息方法
public function getEmployeeInfo() {
$info = parent::getEmployeeInfo();
$info['type'] = '技术员';
$info['skill_level'] = $this->skillLevel;
$info['overtime_hours'] = $this->overtimeHours;
return $info;
}
// 技术特有方法
public function addOvertime($hours) {
$this->overtimeHours += $hours;
echo "{$this->name} 加班了 {$hours} 小时\n";
}
public function fixBug($bugId) {
echo "技术员{$this->name}修复了Bug #{$bugId}\n";
}
public function work() {
parent::work();
echo "{$this->name} 正在编写代码\n";
}
}
// 使用示例
echo "=== 员工管理系统 ===\n\n";
// 创建员工
$manager = new Manager(1, "张经理", 10000, 3000, "技术部");
$salesperson = new Salesperson(2, "李销售", 5000, 0.05);
$technician = new Technician(3, "王技术", 8000, 3);
// 员工工作
$manager->work();
$salesperson->work();
$technician->work();
echo "\n";
// 特殊操作
$manager->manageTeam();
$manager->approveRequest("购买新服务器");
$salesperson->makeSale(50000);
$salesperson->makeSale(30000);
$technician->fixBug(1001);
$technician->addOvertime(10);
echo "\n=== 员工薪资信息 ===\n";
// 显示所有员工信息
$employees = [$manager, $salesperson, $technician];
foreach ($employees as $employee) {
$info = $employee->getEmployeeInfo();
echo "ID: {$info['id']}\n";
echo "姓名: {$info['name']}\n";
echo "类型: {$info['type']}\n";
echo "基础工资: {$employee->baseSalary}\n";
echo "实际工资: {$info['salary']}\n";
if (isset($info['department'])) {
echo "部门: {$info['department']}\n";
}
if (isset($info['sales_amount'])) {
echo "销售额: {$info['sales_amount']}\n";
echo "提成: {$info['commission']}\n";
}
if (isset($info['skill_level'])) {
echo "技能等级: {$info['skill_level']}\n";
}
echo "----------------\n";
}
?>
继承的优点和注意事项
继承的优点
- 代码重用:子类可以重用父类的代码
- 逻辑清晰:建立清晰的类层次结构
- 易于维护:修改父类可以影响所有子类
- 扩展性好:可以轻松添加新的子类
继承的注意事项
<?php
// 1. 单继承限制:PHP只支持单继承
class A {}
class B {}
class C extends A {} // ✅ 正确
// class D extends A, B {} // ❌ 错误,不能多继承
// 2. 构造函数链:记得调用父类构造函数
class ParentClass {
protected $value;
public function __construct($value) {
$this->value = $value;
}
}
class ChildClass extends ParentClass {
public function __construct($value) {
parent::__construct($value); // 不要忘记调用
}
}
// 3. 方法重写时保持兼容性
class Bird {
public function fly() {
return "鸟在飞";
}
}
class Penguin extends Bird {
// 重写方法时要考虑逻辑一致性
public function fly() {
return "企鹅不能飞,但会游泳";
}
}
// 4. 避免过深的继承层次
// 太深的继承会难以理解和维护
// 一般建议继承层次不超过3-4层
?>
继承与组合
有时候,使用组合比继承更合适:
<?php
// 继承的方式
class CarWithInheritance extends Vehicle {
private $engine;
public function __construct() {
$this->engine = new Engine(); // 组合
}
public function start() {
$this->engine->start(); // 使用组合对象
parent::start();
}
}
// 组合的方式
class CarWithComposition {
private $vehicle;
private $engine;
public function __construct() {
$this->vehicle = new Vehicle();
$this->engine = new Engine();
}
public function start() {
$this->engine->start();
return $this->vehicle->start();
}
}
// 选择原则:
// - IS-A关系(是一个):使用继承
// - HAS-A关系(有一个):使用组合
?>
通过本节的学习,你应该掌握了PHP中继承的基本概念和用法。继承是面向对象编程的重要特性,合理使用继承可以让代码更加清晰、可维护和可扩展。