封装与继承
封装和继承是面向对象编程的两个核心概念。封装帮助我们保护数据和控制访问,而继承则让我们能够重用和扩展现有代码。这两个特性共同构建了面向对象编程的基础架构。
学习目标
完成本节学习后,你将能够:
- 理解封装的概念和重要性
- 掌握PHP的访问控制修饰符(public、protected、private)
- 学会使用getter和setter方法
- 理解继承的概念和优势
- 掌握extends关键字的使用
- 学会使用parent关键字访问父类成员
- 理解方法重写和parent::语法
- 了解继承中的构造函数调用
封装(Encapsulation)
什么是封装
封装是将数据(属性)和操作数据的方法(行为)捆绑在一起,并对外部隐藏对象的内部实现细节。封装提供了以下好处:
- 数据保护:防止外部代码直接修改对象内部状态
- 访问控制:通过公共接口控制对数据的访问
- 实现隐藏:隐藏内部实现细节,降低复杂性
- 维护性:可以修改内部实现而不影响外部代码
访问控制修饰符
PHP提供了三个访问控制修饰符:
1. public(公共的)
- 可以在任何地方访问
- 类内部、子类、类外部都可以访问
2. protected(受保护的)
- 只能在类内部和子类中访问
- 类外部无法直接访问
3. private(私有的)
- 只能在定义它的类内部访问
- 子类也无法访问
基本封装示例
<?php
class BankAccount {
// 私有属性:只能通过类的方法访问
private $accountNumber;
private $balance;
private $ownerName;
private $isLocked = false;
// 受保护的属性:子类可以访问
protected $accountType;
protected $createdDate;
// 公有属性:任何地方都可以访问(通常不推荐)
public $bankName = "示例银行";
// 构造函数
public function __construct($accountNumber, $ownerName, $initialBalance = 0) {
$this->accountNumber = $this->validateAccountNumber($accountNumber);
$this->ownerName = $ownerName;
$this->balance = $this->validateBalance($initialBalance);
$this->accountType = "储蓄账户";
$this->createdDate = date('Y-m-d H:i:s');
echo "创建账户:{$this->accountNumber},持有人:{$this->ownerName}\n";
}
// 公有方法:外部接口
public function deposit($amount) {
if ($this->isLocked) {
throw new Exception("账户已锁定,无法存款");
}
$amount = $this->validateAmount($amount);
$this->balance += $amount;
echo "存入:¥{$amount},余额:¥{$this->balance}\n";
return $this->balance;
}
public function withdraw($amount) {
if ($this->isLocked) {
throw new Exception("账户已锁定,无法取款");
}
$amount = $this->validateAmount($amount);
if ($this->balance < $amount) {
throw new Exception("余额不足");
}
$this->balance -= $amount;
echo "取出:¥{$amount},余额:¥{$this->balance}\n";
return $this->balance;
}
public function getBalance() {
return $this->balance;
}
public function getAccountNumber() {
return $this->maskAccountNumber($this->accountNumber);
}
public function getOwnerName() {
return $this->ownerName;
}
public function lock() {
$this->isLocked = true;
echo "账户 {$this->accountNumber} 已锁定\n";
}
public function unlock() {
$this->isLocked = false;
echo "账户 {$this->accountNumber} 已解锁\n";
}
// 受保护的方法:子类可以访问
protected function validateAmount($amount) {
if (!is_numeric($amount) || $amount <= 0) {
throw new Exception("金额必须是正数");
}
return (float)$amount;
}
protected function validateAccountNumber($accountNumber) {
if (empty($accountNumber) || strlen($accountNumber) < 10) {
throw new Exception("账户号码格式不正确");
}
return $accountNumber;
}
protected function validateBalance($balance) {
if (!is_numeric($balance) || $balance < 0) {
throw new Exception("初始余额必须是非负数");
}
return (float)$balance;
}
protected function maskAccountNumber($accountNumber) {
return substr($accountNumber, 0, 4) . '****' . substr($accountNumber, -4);
}
// 私有方法:只有类内部可以访问
private function logTransaction($type, $amount) {
$timestamp = date('Y-m-d H:i:s');
echo "[$timestamp] {$type}: ¥{$amount}\n";
}
public function getAccountInfo() {
return [
'account_number' => $this->getAccountNumber(),
'owner' => $this->ownerName,
'balance' => $this->balance,
'type' => $this->accountType,
'created_date' => $this->createdDate,
'is_locked' => $this->isLocked
];
}
}
// 使用银行账户类
echo "=== 基本封装示例 ===\n";
try {
$account = new BankAccount("1234567890", "张三", 1000.00);
// 通过公有方法访问
echo "账户信息:\n";
echo "账号:{$account->getAccountNumber()}\n";
echo "户主:{$account->getOwnerName()}\n";
echo "余额:¥{$account->getBalance()}\n";
// 进行操作
$account->deposit(500.00);
$account->withdraw(200.00);
// 访问公共属性
echo "银行:{$account->bankName}\n";
// 这些操作会导致错误:
// echo $account->accountNumber; // 错误:无法访问私有属性
// echo $account->balance; // 错误:无法访问私有属性
// $account->balance = 10000; // 错误:无法修改私有属性
} catch (Exception $e) {
echo "错误:" . $e->getMessage() . "\n";
}
?>
Getter和Setter方法
Getter和Setter方法提供了一种受控的方式来访问和修改私有属性。
<?php
class Product {
private $id;
private $name;
private $price;
private $description;
private $inStock;
private $minStockLevel = 10;
public function __construct($id, $name, $price) {
$this->id = $this->validateId($id);
$this->name = $this->validateName($name);
$this->price = $this->validatePrice($price);
$this->inStock = true;
}
// Getter方法
public function getId() {
return $this->id;
}
public function getName() {
return $this->name;
}
public function getPrice() {
return $this->price;
}
public function getDescription() {
return $this->description ?: '暂无描述';
}
public function isInStock() {
return $this->inStock;
}
public function getMinStockLevel() {
return $this->minStockLevel;
}
// Setter方法(带验证)
public function setName($name) {
$this->name = $this->validateName($name);
echo "产品名称已更新为:{$this->name}\n";
}
public function setPrice($price) {
$this->price = $this->validatePrice($price);
echo "产品价格已更新为:¥{$this->price}\n";
}
public function setDescription($description) {
$this->description = $this->validateDescription($description);
echo "产品描述已更新\n";
}
public function setInStock($inStock) {
$this->inStock = (bool)$inStock;
echo "产品库存状态:" . ($this->inStock ? "有货" : "缺货") . "\n";
}
public function setMinStockLevel($level) {
$this->minStockLevel = $this->validateStockLevel($level);
echo "最小库存警戒线设置为:{$this->minStockLevel}\n";
}
// 带业务逻辑的设置方法
public function applyDiscount($percentage) {
if ($percentage <= 0 || $percentage > 100) {
throw new Exception("折扣百分比必须在0-100之间");
}
$discount = $this->price * ($percentage / 100);
$this->price -= $discount;
echo "应用 {$percentage}% 折扣,折扣金额:¥{$discount}\n";
echo "折后价格:¥{$this->price}\n";
return $this->price;
}
public function increasePrice($amount) {
if ($amount <= 0) {
throw new Exception("增加金额必须为正数");
}
$this->price += $amount;
echo "价格增加:¥{$amount},新价格:¥{$this->price}\n";
return $this->price;
}
// 验证方法
private function validateId($id) {
if (empty($id)) {
throw new Exception("产品ID不能为空");
}
return $id;
}
private function validateName($name) {
if (empty($name)) {
throw new Exception("产品名称不能为空");
}
if (strlen($name) > 100) {
throw new Exception("产品名称过长");
}
return trim($name);
}
private function validatePrice($price) {
if (!is_numeric($price) || $price < 0) {
throw new Exception("价格必须是非负数");
}
return (float)$price;
}
private function validateDescription($description) {
if (strlen($description) > 500) {
throw new Exception("描述过长,最多500字符");
}
return $description;
}
private function validateStockLevel($level) {
if (!is_numeric($level) || $level < 0) {
throw new Exception("库存警戒线必须是非负数");
}
return (int)$level;
}
// 只读属性(只有getter)
public function getFormattedPrice() {
return '¥' . number_format($this->price, 2);
}
public function getProductInfo() {
return [
'id' => $this->id,
'name' => $this->name,
'price' => $this->getFormattedPrice(),
'description' => $this->getDescription(),
'in_stock' => $this->isInStock(),
'min_stock_level' => $this->minStockLevel
];
}
}
// 使用Getter和Setter
echo "=== Getter和Setter方法示例 ===\n";
try {
$product = new Product("P001", "智能手机", 2999.00);
echo "\n初始产品信息:\n";
print_r($product->getProductInfo());
echo "\n修改产品属性:\n";
$product->setName("智能手机 Pro");
$product->setPrice(3299.00);
$product->setDescription("新款智能手机,配置更强大");
echo "\n应用折扣:\n";
$product->applyDiscount(10);
echo "\n最终产品信息:\n";
print_r($product->getProductInfo());
} catch (Exception $e) {
echo "错误:" . $e->getMessage() . "\n";
}
?>
高级封装技巧
<?php
class Configuration {
private $settings = [];
private $readOnly = [];
private $validatorCallbacks = [];
public function __construct() {
// 初始化默认配置
$this->initializeDefaults();
}
// 设置配置值
public function set($key, $value) {
if ($this->isReadOnly($key)) {
throw new Exception("配置项 '$key' 为只读");
}
$oldValue = $this->get($key);
// 执行验证回调
if (isset($this->validatorCallbacks[$key])) {
$callback = $this->validatorCallbacks[$key];
if (!$callback($value)) {
throw new Exception("配置项 '$key' 的值无效");
}
}
$this->settings[$key] = $value;
if ($oldValue !== $value) {
$this->onConfigChange($key, $oldValue, $value);
}
return $this;
}
// 获取配置值
public function get($key, $default = null) {
return $this->settings[$key] ?? $default;
}
// 批量设置
public function setMultiple(array $settings) {
foreach ($settings as $key => $value) {
$this->set($key, $value);
}
return $this;
}
// 检查配置是否存在
public function has($key) {
return array_key_exists($key, $this->settings);
}
// 删除配置项
public function remove($key) {
if ($this->isReadOnly($key)) {
throw new Exception("无法删除只读配置项 '$key'");
}
unset($this->settings[$key]);
return $this;
}
// 设置只读配置
public function setReadOnly($key) {
$this->readOnly[$key] = true;
return $this;
}
// 设置验证器
public function setValidator($key, callable $validator) {
$this->validatorCallbacks[$key] = $validator;
return $this;
}
// 获取所有配置
public function all() {
return $this->settings;
}
// 清空所有非只读配置
public function clear() {
$readOnlySettings = array_intersect_key($this->settings, $this->readOnly);
$this->settings = $readOnlySettings;
return $this;
}
// 从数组加载配置
public function loadFromArray(array $config) {
$this->settings = array_merge($this->settings, $config);
return $this;
}
// 保存到数组
public function toArray() {
return $this->settings;
}
// 魔术方法:支持数组式访问
public function __get($key) {
return $this->get($key);
}
public function __set($key, $value) {
$this->set($key, $value);
}
public function __isset($key) {
return $this->has($key);
}
public function __unset($key) {
$this->remove($key);
}
// 私有方法
private function isReadOnly($key) {
return isset($this->readOnly[$key]);
}
private function initializeDefaults() {
$this->settings = [
'app_name' => 'MyApp',
'version' => '1.0.0',
'debug' => false,
'timezone' => 'Asia/Shanghai',
'max_connections' => 100,
'timeout' => 30
];
// 设置只读配置
$this->setReadOnly('version');
// 设置验证器
$this->setValidator('debug', function($value) {
return is_bool($value);
});
$this->setValidator('max_connections', function($value) {
return is_int($value) && $value > 0 && $value <= 1000;
});
}
private function onConfigChange($key, $oldValue, $newValue) {
echo "配置变更:$key 从 '$oldValue' 改为 '$newValue'\n";
}
}
// 使用高级封装的配置类
echo "=== 高级封装技巧示例 ===\n";
try {
$config = new Configuration();
echo "\n初始配置:\n";
print_r($config->all());
echo "\n修改配置:\n";
$config->set('debug', true);
$config->set('max_connections', 50);
echo "\n尝试设置只读配置(会失败):\n";
try {
$config->set('version', '2.0.0');
} catch (Exception $e) {
echo "预期错误:" . $e->getMessage() . "\n";
}
echo "\n尝试设置无效值(会失败):\n";
try {
$config->set('max_connections', -1);
} catch (Exception $e) {
echo "预期错误:" . $e->getMessage() . "\n";
}
echo "\n使用魔术方法访问配置:\n";
echo "应用名称:{$config->app_name}\n";
echo "调试模式:" . ($config->debug ? '开启' : '关闭') . "\n";
// 数组式访问
if (isset($config->debug)) {
echo "调试模式已设置\n";
}
} catch (Exception $e) {
echo "错误:" . $e->getMessage() . "\n";
}
?>
继承(Inheritance)
什么是继承
继承允许一个类(子类)获得另一个类(父类)的属性和方法。继承提供了以下好处:
- 代码重用:子类可以重用父类的代码
- 扩展功能:在父类基础上添加新功能
- 层次结构:创建清晰的类层次关系
- 多态支持:为多态提供基础
基本继承语法
<?php
class ParentClass {
// 父类的属性和方法
}
class ChildClass extends ParentClass {
// 子类的新属性和方法
}
?>
基本继承示例
<?php
// 父类:动物
class Animal {
protected $name;
protected $age;
protected $species;
public function __construct($name, $age, $species) {
$this->name = $name;
$this->age = $age;
$this->species = $species;
echo "创建了一个 {$this->species}:{$this->name}\n";
}
public function eat() {
echo "{$this->name} 正在吃东西\n";
}
public function sleep() {
echo "{$this->name} 正在睡觉\n";
}
public function makeSound() {
echo "{$this->name} 发出了声音\n";
}
public function getAge() {
return $this->age;
}
public function getName() {
return $this->name;
}
public function getSpecies() {
return $this->species;
}
public function celebrateBirthday() {
$this->age++;
echo "{$this->name} 过生日了,现在 {$this->age} 岁!\n";
}
public function getInfo() {
return "这是一只 {$this->age} 岁的 {$this->species},名字叫 {$this->name}";
}
}
// 子类:狗
class Dog extends Animal {
private $breed;
public function __construct($name, $age, $breed) {
// 调用父类构造函数
parent::__construct($name, $age, "狗");
$this->breed = $breed;
echo "这是一只 {$this->breed}\n";
}
// 新增方法
public function wagTail() {
echo "{$this->name} 摇着尾巴\n";
}
public function fetch($item) {
echo "{$this->name} 去取 {$item}\n";
}
// 重写父类方法
public function makeSound() {
echo "{$this->name} 汪汪叫\n";
}
// 扩展父类方法
public function getInfo() {
$parentInfo = parent::getInfo();
return $parentInfo . ",品种是 {$this->breed}";
}
public function getBreed() {
return $this->breed;
}
}
// 子类:猫
class Cat extends Animal {
private $color;
private $isIndoor;
public function __construct($name, $age, $color, $isIndoor = true) {
parent::__construct($name, $age, "猫");
$this->color = $color;
$this->isIndoor = $isIndoor;
echo "这是一只 {$this->color} 的" . ($this->isIndoor ? "室内" : "室外") . "猫\n";
}
// 新增方法
public function purr() {
echo "{$this->name} 发出呼噜声\n";
}
public function scratch() {
echo "{$this->name} 磨爪子\n";
}
public function climb() {
echo "{$this->name} 爬到了高处\n";
}
// 重写父类方法
public function makeSound() {
echo "{$this->name} 喵喵叫\n";
$this->purr();
}
// 扩展父类方法
public function getInfo() {
$parentInfo = parent::getInfo();
return $parentInfo . ",颜色是 {$this->color}," .
($this->isIndoor ? "室内" : "室外") . "猫";
}
public function getColor() {
return $this->color;
}
public function isIndoor() {
return $this->isIndoor;
}
}
// 使用继承
echo "=== 基本继承示例 ===\n";
echo "\n创建动物对象:\n";
$dog = new Dog("旺财", 3, "金毛");
$cat = new Cat("咪咪", 2, "橘色");
echo "\n测试狗的行为:\n";
$dog->eat();
$dog->makeSound();
$dog->wagTail();
$dog->fetch("球");
echo "\n测试猫的行为:\n";
$cat->eat();
$cat->makeSound();
$cat->climb();
$cat->scratch();
echo "\n动物信息:\n";
echo $dog->getInfo() . "\n";
echo $cat->getInfo() . "\n";
echo "\n生日庆祝:\n";
$dog->celebrateBirthday();
$cat->celebrateBirthday();
?>
复杂的继承示例
<?php
// 父类:车辆
class Vehicle {
protected $brand;
protected $model;
protected $year;
protected $speed = 0;
protected $maxSpeed;
protected $fuel = 100;
protected $isRunning = false;
public function __construct($brand, $model, $year, $maxSpeed) {
$this->brand = $brand;
$this->model = $model;
$this->year = $year;
$this->maxSpeed = $maxSpeed;
echo "创建了 {$this->brand} {$this->model} ({$this->year}年)\n";
}
public function start() {
if ($this->fuel <= 0) {
echo "燃料不足,无法启动\n";
return false;
}
if (!$this->isRunning) {
$this->isRunning = true;
echo "{$this->brand} {$this->model} 启动了\n";
return true;
} else {
echo "车辆已经在运行中\n";
return true;
}
}
public function stop() {
if ($this->isRunning) {
$this->speed = 0;
$this->isRunning = false;
echo "{$this->brand} {$this->model} 停止了\n";
} else {
echo "车辆已经停止\n";
}
return true;
}
public function accelerate($amount) {
if (!$this->isRunning) {
echo "请先启动车辆\n";
return false;
}
$newSpeed = $this->speed + $amount;
if ($newSpeed > $this->maxSpeed) {
echo "不能超过最高速度 {$this->maxSpeed} km/h\n";
return false;
}
$this->speed = $newSpeed;
$this->consumeFuel($amount * 0.1);
echo "加速到 {$this->speed} km/h\n";
return true;
}
public function brake($amount) {
if ($this->speed >= $amount) {
$this->speed -= $amount;
} else {
$this->speed = 0;
}
echo "减速到 {$this->speed} km/h\n";
return $this->speed;
}
public function refuel($amount) {
$this->fuel = min(100, $this->fuel + $amount);
echo "加油 {$amount}%,当前燃料:{$this->fuel}%\n";
}
public function getFuel() {
return $this->fuel;
}
public function getSpeed() {
return $this->speed;
}
public function isRunning() {
return $this->isRunning;
}
public function getMaxSpeed() {
return $this->maxSpeed;
}
public function getVehicleInfo() {
return [
'brand' => $this->brand,
'model' => $this->model,
'year' => $this->year,
'speed' => $this->speed,
'max_speed' => $this->maxSpeed,
'fuel' => $this->fuel,
'is_running' => $this->isRunning
];
}
protected function consumeFuel($amount) {
$this->fuel = max(0, $this->fuel - $amount);
if ($this->fuel <= 10) {
echo "警告:燃料不足!\n";
}
if ($this->fuel <= 0) {
$this->stop();
echo "燃料耗尽,车辆停止\n";
}
}
}
// 子类:汽车
class Car extends Vehicle {
private $doors;
private $trunkSize;
private $isConvertible;
public function __construct($brand, $model, $year, $maxSpeed, $doors, $trunkSize, $isConvertible = false) {
parent::__construct($brand, $model, $year, $maxSpeed);
$this->doors = $doors;
$this->trunkSize = $trunkSize;
$this->isConvertible = $isConvertible;
}
public function openTrunk() {
echo "打开了后备箱(容量:{$this->trunkSize}L)\n";
}
public function closeTrunk() {
echo "关闭了后备箱\n";
}
public function honk() {
echo "嘀嘀!\n";
}
public function turnOnAirConditioner() {
echo "打开空调\n";
}
public function playRadio($station) {
echo "收音机调到 {$station} 频道\n";
}
public function openRoof() {
if ($this->isConvertible) {
echo "打开了敞篷\n";
} else {
echo "这辆车不是敞篷车\n";
}
}
public function closeRoof() {
if ($this->isConvertible) {
echo "关闭了敞篷\n";
}
}
public function getDoors() {
return $this->doors;
}
public function getTrunkSize() {
return $this->trunkSize;
}
public function isConvertible() {
return $this->isConvertible;
}
public function getVehicleInfo() {
$info = parent::getVehicleInfo();
$info['doors'] = $this->doors;
$info['trunk_size'] = $this->trunkSize;
$info['is_convertible'] = $this->isConvertible;
return $info;
}
}
// 子类:摩托车
class Motorcycle extends Vehicle {
private $engineCC;
private $hasWindshield;
private $type; // 跑车、巡航车等
public function __construct($brand, $model, $year, $maxSpeed, $engineCC, $hasWindshield = false, $type = "普通") {
parent::__construct($brand, $model, $year, $maxSpeed);
$this->engineCC = $engineCC;
$this->hasWindshield = $hasWindshield;
$this->type = $type;
}
public function wheelie() {
if ($this->speed >= 20 && $this->speed <= 60) {
echo "翘起前轮!\n";
} else {
echo "速度不适合做翘头动作\n";
}
}
public function lean($direction) {
if ($this->speed >= 30) {
echo "向{$direction}倾斜转弯\n";
} else {
echo "速度太慢,无法倾斜\n";
}
}
public function installWindshield() {
if (!$this->hasWindshield) {
$this->hasWindshield = true;
echo "安装了挡风玻璃\n";
} else {
echo "已经有挡风玻璃了\n";
}
}
public function removeWindshield() {
if ($this->hasWindshield) {
$this->hasWindshield = false;
echo "拆卸了挡风玻璃\n";
} else {
echo "没有挡风玻璃可拆卸\n";
}
}
// 重写父类方法:摩托车燃料消耗不同
protected function consumeFuel($amount) {
parent::consumeFuel($amount * 0.7); // 摩托车更省油
}
public function getEngineCC() {
return $this->engineCC;
}
public function hasWindshield() {
return $this->hasWindshield;
}
public function getType() {
return $this->type;
}
public function getVehicleInfo() {
$info = parent::getVehicleInfo();
$info['engine_cc'] = $this->engineCC;
$info['has_windshield'] = $this->hasWindshield;
$info['type'] = $this->type;
return $info;
}
}
// 使用复杂继承
echo "=== 复杂继承示例 ===\n";
echo "\n创建车辆:\n";
$car = new Car("特斯拉", "Model 3", 2023, 225, 4, 425, false);
$motorcycle = new Motorcycle("本田", "CBR600RR", 2022, 260, 600, true, "跑车");
echo "\n测试汽车:\n";
$car->start();
$car->accelerate(50);
$car->honk();
$car->turnOnAirConditioner();
$car->openTrunk();
$car->getVehicleInfo();
echo "\n测试摩托车:\n";
$motorcycle->start();
$motorcycle->accelerate(40);
$motorcycle->wheelie();
$motorcycle->lean("左");
$motorcycle->accelerate(80);
$motorcycle->wheelie();
echo "\n车辆信息对比:\n";
echo "汽车:\n";
print_r($car->getVehicleInfo());
echo "\n摩托车:\n";
print_r($motorcycle->getVehicleInfo());
?>
继承中的构造函数
<?php
// 父类:用户
class User {
protected $id;
protected $username;
protected $email;
protected $passwordHash;
protected $createdAt;
protected $lastLogin;
protected $isActive = true;
public function __construct($username, $email, $password) {
$this->id = uniqid('user_');
$this->username = $this->validateUsername($username);
$this->email = $this->validateEmail($email);
$this->passwordHash = $this->hashPassword($password);
$this->createdAt = date('Y-m-d H:i:s');
echo "创建用户:{$this->username}\n";
}
protected function validateUsername($username) {
if (empty($username) || strlen($username) < 3) {
throw new Exception("用户名至少需要3个字符");
}
return $username;
}
protected function validateEmail($email) {
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new Exception("邮箱格式不正确");
}
return $email;
}
protected function hashPassword($password) {
if (strlen($password) < 6) {
throw new Exception("密码至少需要6个字符");
}
return password_hash($password, PASSWORD_DEFAULT);
}
public function login($password) {
if (!$this->isActive) {
throw new Exception("账户已被禁用");
}
if (password_verify($password, $this->passwordHash)) {
$this->lastLogin = date('Y-m-d H:i:s');
echo "用户 {$this->username} 登录成功\n";
return true;
} else {
throw new Exception("密码错误");
}
}
public function logout() {
echo "用户 {$this->username} 已登出\n";
}
public function activate() {
$this->isActive = true;
echo "账户 {$this->username} 已激活\n";
}
public function deactivate() {
$this->isActive = false;
echo "账户 {$this->username} 已禁用\n";
}
// Getter方法
public function getId() { return $this->id; }
public function getUsername() { return $this->username; }
public function getEmail() { return $this->email; }
public function getCreatedAt() { return $this->createdAt; }
public function getLastLogin() { return $this->lastLogin; }
public function isActive() { return $this->isActive; }
public function getUserInfo() {
return [
'id' => $this->id,
'username' => $this->username,
'email' => $this->email,
'created_at' => $this->createdAt,
'last_login' => $this->lastLogin,
'is_active' => $this->isActive
];
}
}
// 子类:管理员
class Admin extends User {
private $adminLevel;
private $permissions;
private $department;
public function __construct($username, $email, $password, $adminLevel = 1, $department = '系统') {
// 先调用父类构造函数
parent::__construct($username, $email, $password);
// 然后初始化子类特有属性
$this->adminLevel = $this->validateAdminLevel($adminLevel);
$this->department = $department;
$this->permissions = $this->getDefaultPermissions();
echo "管理员 {$this->username} (级别:{$this->adminLevel}) 已创建\n";
}
private function validateAdminLevel($level) {
if (!is_int($level) || $level < 1 || $level > 5) {
throw new Exception("管理员级别必须在1-5之间");
}
return $level;
}
private function getDefaultPermissions() {
$permissions = ['user_management'];
if ($this->adminLevel >= 2) {
$permissions[] = 'content_management';
}
if ($this->adminLevel >= 3) {
$permissions[] = 'system_config';
}
if ($this->adminLevel >= 4) {
$permissions[] = 'data_export';
}
if ($this->adminLevel >= 5) {
$permissions[] = 'system_admin';
}
return $permissions;
}
public function hasPermission($permission) {
return in_array($permission, $this->permissions);
}
public function addPermission($permission) {
if (!$this->hasPermission($permission)) {
$this->permissions[] = $permission;
echo "管理员 {$this->username} 获得权限:{$permission}\n";
}
return $this;
}
public function removePermission($permission) {
if ($this->hasPermission($permission) && $permission !== 'user_management') {
$key = array_search($permission, $this->permissions);
unset($this->permissions[$key]);
$this->permissions = array_values($this->permissions);
echo "管理员 {$this->username} 失去权限:{$permission}\n";
}
return $this;
}
public function manageUsers() {
if ($this->hasPermission('user_management')) {
echo "管理员 {$this->username} 正在管理用户\n";
} else {
throw new Exception("没有用户管理权限");
}
}
public function configureSystem() {
if ($this->hasPermission('system_config')) {
echo "管理员 {$this->username} 正在配置系统\n";
} else {
throw new Exception("没有系统配置权限");
}
}
public function exportData() {
if ($this->hasPermission('data_export')) {
echo "管理员 {$this->username} 正在导出数据\n";
} else {
throw new Exception("没有数据导出权限");
}
}
// 重写父类方法
public function getUserInfo() {
$info = parent::getUserInfo();
$info['admin_level'] = $this->adminLevel;
$info['department'] = $this->department;
$info['permissions'] = $this->permissions;
return $info;
}
// Getter方法
public function getAdminLevel() { return $this->adminLevel; }
public function getDepartment() { return $this->department; }
public function getPermissions() { return $this->permissions; }
}
// 子类:VIP用户
class VIPUser extends User {
private $vipLevel;
private $expirationDate;
private $specialFeatures;
public function __construct($username, $email, $password, $vipLevel = 1, $duration = '1 year') {
parent::__construct($username, $email, $password);
$this->vipLevel = $this->validateVipLevel($vipLevel);
$this->expirationDate = $this->calculateExpirationDate($duration);
$this->specialFeatures = $this->getVipFeatures();
echo "VIP用户 {$this->username} (级别:{$this->vipLevel}) 已创建\n";
echo "有效期至:{$this->expirationDate}\n";
}
private function validateVipLevel($level) {
if (!is_int($level) || $level < 1 || $level > 3) {
throw new Exception("VIP级别必须在1-3之间");
}
return $level;
}
private function calculateExpirationDate($duration) {
$date = new DateTime();
if ($duration === '6 months') {
$date->add(new DateInterval('P6M'));
} elseif ($duration === '1 year') {
$date->add(new DateInterval('P1Y'));
} elseif ($duration === '2 years') {
$date->add(new DateInterval('P2Y'));
}
return $date->format('Y-m-d');
}
private function getVipFeatures() {
$features = ['priority_support'];
if ($this->vipLevel >= 2) {
$features[] = 'exclusive_content';
$features[] = 'no_ads';
}
if ($this->vipLevel >= 3) {
$features[] = 'unlimited_downloads';
$features[] = 'personal_manager';
}
return $features;
}
public function isVipActive() {
return $this->expirationDate >= date('Y-m-d');
}
public function extendVip($duration) {
$currentDate = new DateTime($this->expirationDate);
if ($duration === '6 months') {
$currentDate->add(new DateInterval('P6M'));
} elseif ($duration === '1 year') {
$currentDate->add(new DateInterval('P1Y'));
}
$this->expirationDate = $currentDate->format('Y-m-d');
echo "VIP已延期至 {$this->expirationDate}\n";
}
public function hasFeature($feature) {
return in_array($feature, $this->specialFeatures) && $this->isVipActive();
}
public function accessExclusiveContent() {
if ($this->hasFeature('exclusive_content')) {
echo "VIP用户 {$this->username} 正在访问独占内容\n";
} else {
throw new Exception("没有访问独占内容的权限");
}
}
public function downloadFile($filename) {
if ($this->hasFeature('unlimited_downloads')) {
echo "VIP用户 {$this->username} 正在下载 {$filename}\n";
} else {
echo "下载次数受限,请升级VIP\n";
}
}
// 重写父类方法
public function getUserInfo() {
$info = parent::getUserInfo();
$info['vip_level'] = $this->vipLevel;
$info['expiration_date'] = $this->expirationDate;
$info['special_features'] = $this->specialFeatures;
$info['is_vip_active'] = $this->isVipActive();
return $info;
}
// Getter方法
public function getVipLevel() { return $this->vipLevel; }
public function getExpirationDate() { return $this->expirationDate; }
public function getSpecialFeatures() { return $this->specialFeatures; }
}
// 使用继承中的构造函数
echo "=== 继承中的构造函数示例 ===\n";
try {
echo "\n创建不同类型的用户:\n";
$user = new User("普通用户", "user@example.com", "password123");
$admin = new Admin("系统管理员", "admin@example.com", "adminpass", 3, "技术部");
$vip = new VIPUser("VIP会员", "vip@example.com", "vippass", 2, "1 year");
echo "\n用户登录测试:\n";
$user->login("password123");
$admin->login("adminpass");
$vip->login("vippass");
echo "\n管理员权限测试:\n";
$admin->manageUsers();
$admin->configureSystem();
try {
$admin->exportData(); // 可能失败,取决于管理员级别
} catch (Exception $e) {
echo $e->getMessage() . "\n";
}
echo "\nVIP功能测试:\n";
$vip->accessExclusiveContent();
$vip->downloadFile("movie.mp4");
echo "\n用户信息对比:\n";
echo "普通用户:\n";
print_r($user->getUserInfo());
echo "\n管理员:\n";
print_r($admin->getUserInfo());
echo "\nVIP用户:\n";
print_r($vip->getUserInfo());
} catch (Exception $e) {
echo "错误:" . $e->getMessage() . "\n";
}
?>
多层继承示例
<?php
// 基础类:员工
class Employee {
protected $id;
protected $name;
protected $position;
protected $salary;
protected $hireDate;
protected $department;
public function __construct($name, $position, $salary, $department) {
$this->id = uniqid('emp_');
$this->name = $name;
$this->position = $position;
$this->salary = $salary;
$this->department = $department;
$this->hireDate = date('Y-m-d');
echo "雇佣员工:{$this->name} ({$this->position})\n";
}
public function work() {
echo "{$this->name} 正在工作\n";
}
public function takeBreak() {
echo "{$this->name} 正在休息\n";
}
public function getAnnualSalary() {
return $this->salary * 12;
}
public function getYearsOfService() {
$hireDate = new DateTime($this->hireDate);
$currentDate = new DateTime();
return $currentDate->diff($hireDate)->y;
}
public function giveRaise($percentage) {
$increase = $this->salary * ($percentage / 100);
$this->salary += $increase;
echo "{$this->name} 获得加薪:¥{$increase},新工资:¥{$this->salary}\n";
}
public function getEmployeeInfo() {
return [
'id' => $this->id,
'name' => $this->name,
'position' => $this->position,
'salary' => $this->salary,
'department' => $this->department,
'hire_date' => $this->hireDate,
'years_of_service' => $this->getYearsOfService()
];
}
// Getter方法
public function getId() { return $this->id; }
public function getName() { return $this->name; }
public function getPosition() { return $this->position; }
public function getSalary() { return $this->salary; }
public function getDepartment() { return $this->department; }
}
// 第二层:经理(继承员工)
class Manager extends Employee {
private $teamSize;
private $managedEmployees = [];
private $bonus;
public function __construct($name, $department, $salary, $teamSize = 0) {
parent::__construct($name, "经理", $salary, $department);
$this->teamSize = $teamSize;
$this->bonus = 0;
}
public function addEmployee(Employee $employee) {
$this->managedEmployees[] = $employee;
$this->teamSize = count($this->managedEmployees);
echo "经理 {$this->name} 现在管理 {$this->teamSize} 名员工\n";
}
public function removeEmployee($employeeId) {
foreach ($this->managedEmployees as $key => $employee) {
if ($employee->getId() === $employeeId) {
unset($this->managedEmployees[$key]);
$this->managedEmployees = array_values($this->managedEmployees);
$this->teamSize = count($this->managedEmployees);
echo "移除员工,当前团队规模:{$this->teamSize}\n";
return true;
}
}
return false;
}
public function conductMeeting() {
echo "经理 {$this->name} 正在主持会议\n";
}
public function assignTask($task) {
echo "经理 {$this->name} 分配任务:{$task}\n";
}
public function evaluatePerformance() {
echo "经理 {$this->name} 正在进行绩效评估\n";
$this->awardBonus(1000);
}
protected function awardBonus($amount) {
$this->bonus += $amount;
echo "经理 {$this->name} 获得奖金:¥{$amount}\n";
}
public function getTotalCompensation() {
return $this->getAnnualSalary() + $this->bonus;
}
public function getTeamMembers() {
return $this->managedEmployees;
}
public function getTeamSize() {
return $this->teamSize;
}
// 重写父类方法
public function work() {
echo "经理 {$this->name} 正在管理工作\n";
$this->conductMeeting();
}
public function getEmployeeInfo() {
$info = parent::getEmployeeInfo();
$info['team_size'] = $this->teamSize;
$info['bonus'] = $this->bonus;
$info['total_compensation'] = $this->getTotalCompensation();
$info['managed_employees'] = array_map(function($emp) {
return $emp->getName() . ' (' . $emp->getPosition() . ')';
}, $this->managedEmployees);
return $info;
}
}
// 第三层:总监(继承经理)
class Director extends Manager {
private $managedManagers = [];
private $budget;
private $stockOptions;
public function __construct($name, $department, $salary, $budget = 1000000) {
parent::__construct($name, $department, $salary);
$this->position = "总监";
$this->budget = $budget;
$this->stockOptions = 0;
}
public function addManager(Manager $manager) {
$this->managedManagers[] = $manager;
$this->teamSize += $manager->getTeamSize() + 1; // +1 for the manager
echo "总监 {$this->name} 现在管理 " . count($this->managedManagers) . " 名经理\n";
}
public function approveBudget($amount, $purpose) {
if ($amount <= $this->budget) {
$this->budget -= $amount;
echo "总监 {$this->name} 批准预算:¥{$amount} 用于 {$purpose}\n";
return true;
} else {
echo "预算不足,无法批准\n";
return false;
}
}
public function setCompanyStrategy() {
echo "总监 {$this->name} 正在制定公司战略\n";
}
public function boardMeeting() {
echo "总监 {$this->name} 参加董事会会议\n";
}
public function grantStockOptions($shares) {
$this->stockOptions += $shares;
echo "总监 {$this->name} 获得股票期权:{$shares} 股\n";
}
public function getTotalCompensation() {
$baseCompensation = parent::getTotalCompensation();
$stockValue = $this->stockOptions * 50; // 假设每股50元
return $baseCompensation + $stockValue;
}
// 重写父类方法
public function work() {
echo "总监 {$this->name} 正在进行战略决策\n";
$this->setCompanyStrategy();
$this->boardMeeting();
}
public function getEmployeeInfo() {
$info = parent::getEmployeeInfo();
$info['position'] = '总监';
$info['budget'] = $this->budget;
$info['stock_options'] = $this->stockOptions;
$info['managed_managers'] = array_map(function($manager) {
return $manager->getName() . ' (经理)';
}, $this->managedManagers);
$info['total_team_size'] = $this->teamSize;
return $info;
}
}
// 使用多层继承
echo "=== 多层继承示例 ===\n";
echo "\n创建员工层级:\n";
$employee1 = new Employee("张三", "开发工程师", 8000, "技术部");
$employee2 = new Employee("李四", "测试工程师", 7000, "技术部");
$manager = new Manager("王五", "技术部", 15000);
$director = new Director("赵六", "技术部", 30000, 5000000);
echo "\n构建团队结构:\n";
$manager->addEmployee($employee1);
$manager->addEmployee($employee2);
$director->addManager($manager);
echo "\n模拟工作场景:\n";
$employee1->work();
$manager->work();
$director->work();
echo "\n绩效评估和奖金:\n";
$manager->evaluatePerformance();
$director->awardBonus(5000);
$director->grantStockOptions(1000);
echo "\n预算管理:\n";
$director->approveBudget(100000, "新项目开发");
$director->approveBudget(5000000, "设备采购");
echo "\n员工信息对比:\n";
echo "普通员工:\n";
print_r($employee1->getEmployeeInfo());
echo "\n经理:\n";
print_r($manager->getEmployeeInfo());
echo "\n总监:\n";
print_r($director->getEmployeeInfo());
?>
实际应用示例
电子商务系统中的继承
<?php
// 基础产品类
class Product {
protected $id;
protected $name;
protected $price;
protected $description;
protected $category;
protected $stock;
protected $sku;
protected $weight;
protected $isActive = true;
public function __construct($id, $name, $price, $category) {
$this->id = $id;
$this->name = $name;
$this->price = $price;
$this->category = $category;
$this->sku = $this->generateSKU();
$this->stock = 0;
$this->weight = 0;
$this->description = '';
}
protected function generateSKU() {
return strtoupper(substr($this->name, 0, 3)) . '-' . $this->id;
}
public function setPrice($price) {
$this->price = max(0, (float)$price);
}
public function setStock($stock) {
$this->stock = max(0, (int)$stock);
}
public function setDescription($description) {
$this->description = $description;
}
public function setWeight($weight) {
$this->weight = max(0, (float)$weight);
}
public function getCalculatedPrice() {
return $this->price;
}
public function getShippingWeight() {
return $this->weight;
}
public function isInStock() {
return $this->stock > 0 && $this->isActive;
}
public function activate() {
$this->isActive = true;
}
public function deactivate() {
$this->isActive = false;
}
public function getBasicInfo() {
return [
'id' => $this->id,
'name' => $this->name,
'sku' => $this->sku,
'price' => $this->price,
'category' => $this->category,
'stock' => $this->stock,
'is_active' => $this->isActive
];
}
// Getter方法
public function getId() { return $this->id; }
public function getName() { return $this->name; }
public function getPrice() { return $this->price; }
public function getSku() { return $this->sku; }
public function getStock() { return $this->stock; }
}
// 物理产品类
class PhysicalProduct extends Product {
private $dimensions;
private $requiresShipping = true;
private $shippingCost;
public function __construct($id, $name, $price, $category, $dimensions = []) {
parent::__construct($id, $name, $price, $category);
$this->dimensions = $dimensions;
$this->calculateShippingCost();
}
private function calculateShippingCost() {
$baseCost = 10;
$weightCost = $this->weight * 2;
$this->shippingCost = $baseCost + $weightCost;
}
public function setDimensions($length, $width, $height) {
$this->dimensions = [
'length' => $length,
'width' => $width,
'height' => $height
];
$this->calculateShippingCost();
}
public function getShippingCost() {
return $this->requiresShipping ? $this->shippingCost : 0;
}
public function getCalculatedPrice() {
return parent::getCalculatedPrice() + $this->getShippingCost();
}
public function getBasicInfo() {
$info = parent::getBasicInfo();
$info['type'] = 'physical';
$info['dimensions'] = $this->dimensions;
$info['shipping_cost'] = $this->getShippingCost();
$info['total_price'] = $this->getCalculatedPrice();
return $info;
}
}
// 数字产品类
class DigitalProduct extends Product {
private $fileSize;
private $fileFormat;
private $downloadLimit = 5;
private $downloadExpire = '30 days';
public function __construct($id, $name, $price, $category, $fileSize, $fileFormat) {
parent::__construct($id, $name, $price, $category);
$this->fileSize = $fileSize;
$this->fileFormat = $fileFormat;
$this->weight = 0; // 数字产品没有重量
}
public function setDownloadLimit($limit) {
$this->downloadLimit = max(1, (int)$limit);
}
public function setDownloadExpire($days) {
$this->downloadExpire = $days . ' days';
}
public function getShippingCost() {
return 0; // 数字产品免运费
}
public function getCalculatedPrice() {
return parent::getCalculatedPrice(); // 无运费
}
public function getBasicInfo() {
$info = parent::getBasicInfo();
$info['type'] = 'digital';
$info['file_size'] = $this->fileSize;
$info['file_format'] = $this->fileFormat;
$info['download_limit'] = $this->downloadLimit;
$info['download_expire'] = $this->downloadExpire;
$info['total_price'] = $this->getCalculatedPrice();
return $info;
}
}
// 订阅产品类
class SubscriptionProduct extends Product {
private $billingCycle;
private $duration;
private $autoRenew = true;
private $trialDays = 0;
public function __construct($id, $name, $price, $category, $billingCycle = 'monthly') {
parent::__construct($id, $name, $price, $category);
$this->billingCycle = $billingCycle;
$this->duration = $this->calculateDuration();
$this->weight = 0;
}
private function calculateDuration() {
switch ($this->billingCycle) {
case 'monthly': return 30;
case 'quarterly': return 90;
case 'yearly': return 365;
default: return 30;
}
}
public function setTrialDays($days) {
$this->trialDays = max(0, (int)$days);
}
public function enableAutoRenew($enable = true) {
$this->autoRenew = $enable;
}
public function getCalculatedPrice() {
$monthlyPrice = parent::getCalculatedPrice();
switch ($this->billingCycle) {
case 'monthly': return $monthlyPrice;
case 'quarterly': return $monthlyPrice * 3 * 0.9; // 10% 折扣
case 'yearly': return $monthlyPrice * 12 * 0.8; // 20% 折扣
default: return $monthlyPrice;
}
}
public function getShippingCost() {
return 0; // 订阅产品免运费
}
public function getBasicInfo() {
$info = parent::getBasicInfo();
$info['type'] = 'subscription';
$info['billing_cycle'] = $this->billingCycle;
$info['duration_days'] = $this->duration;
$info['auto_renew'] = $this->autoRenew;
$info['trial_days'] = $this->trialDays;
$info['total_price'] = $this->getCalculatedPrice();
return $info;
}
}
// 使用电子商务产品继承
echo "=== 电子商务系统继承示例 ===\n";
echo "\n创建不同类型的产品:\n";
$laptop = new PhysicalProduct("P001", "笔记本电脑", 5000, "电子产品");
$laptop->setWeight(2.5);
$laptop->setDimensions(35, 25, 2);
$laptop->setStock(50);
$ebook = new DigitalProduct("D001", "PHP编程指南", 29.99, "电子书", "15MB", "PDF");
$ebook->setDownloadLimit(10);
$ebook->setStock(999999); // 数字产品库存不受限制
$vipSubscription = new SubscriptionProduct("S001", "VIP会员", 99, "会员服务", "monthly");
$vipSubscription->setTrialDays(7);
echo "\n产品信息对比:\n";
echo "物理产品:\n";
print_r($laptop->getBasicInfo());
echo "\n数字产品:\n";
print_r($ebook->getBasicInfo());
echo "\n订阅产品:\n";
print_r($vipSubscription->getBasicInfo());
echo "\n价格计算:\n";
echo "笔记本电脑总价(含运费):¥" . $laptop->getCalculatedPrice() . "\n";
echo "电子书价格:¥" . $ebook->getCalculatedPrice() . "\n";
echo "VIP会员年费:¥" . (new SubscriptionProduct("S002", "VIP年费", 99, "会员服务", "yearly"))->getCalculatedPrice() . "\n";
?>
最佳实践和注意事项
封装的最佳实践
- 最小暴露原则:只暴露必要的方法和属性
- 使用访问控制:合理使用public、protected、private
- 提供getter和setter:控制对私有属性的访问
- 验证输入:在setter方法中验证数据
- 保持接口简单:公共接口应该简洁明了
继承的最佳实践
- 遵循"is-a"关系:子类应该是父类的一种特殊类型
- 不要过度继承:优先使用组合而不是继承
- 调用父类构造函数:始终在子类构造函数中调用parent::__construct()
- 小心重写:重写方法时保持向后兼容性
- 了解层次深度:避免过深的继承层次
常见的反模式
<?php
// 反模式1:过度暴露
class BadClass {
public $data; // 应该是private
// 缺少getter/setter,直接暴露内部状态
}
// 反模式2:过度继承
class A extends B extends C extends D extends E {
// 继承层次过深,难以维护
}
// 反模式3:违反"is-a"原则
class Employee extends DatabaseConnection {
// 员工不是数据库连接,应该使用组合
}
// 好的设计模式
class GoodExample {
private $data;
public function getData() {
return $this->data;
}
public function setData($data) {
$this->data = $this->validateData($data);
}
private function validateData($data) {
// 验证逻辑
return $data;
}
}
// 使用组合而不是继承
class Employee {
private $dbConnection;
public function __construct(DatabaseConnection $dbConnection) {
$this->dbConnection = $dbConnection;
}
}
?>
总结
封装和继承是面向对象编程的基石:
关键要点:
-
封装:
- 保护数据和控制访问
- 使用访问控制修饰符
- 提供公共接口
- 实现信息隐藏
-
继承:
- 实现代码重用
- 建立"is-a"关系
- 支持方法重写
- 创建类层次结构
-
访问控制:
- public:任何地方可访问
- protected:类和子类可访问
- private:仅类内部可访问
-
设计原则:
- 最小暴露原则
- 封装变化
- 优先组合而不是继承
- 保持接口简单
最佳实践:
- 合理使用访问控制修饰符
- 通过getter和setter控制属性访问
- 遵循"is-a"关系使用继承
- 在子类中调用parent构造函数
- 避免过深的继承层次
- 优先考虑组合而不是继承
通过掌握封装和继承,你可以构建更加结构化、可维护和可扩展的面向对象应用程序。这些概念为更高级的OOP特性如接口、抽象类和多态奠定了基础。