继承和Trait
概述
继承是面向对象编程的核心概念之一,允许一个类继承另一个类的属性和方法。PHP支持单继承,同时提供了Trait机制来实现代码复用。本章将深入学习类继承、抽象类、接口以及Trait的使用。
类继承基础
基本继承语法
php
<?php
// 父类(基类)
class Vehicle {
protected $brand;
protected $speed;
public function __construct($brand) {
$this->brand = $brand;
$this->speed = 0;
}
public function start() {
echo "{$this->brand} 启动了\n";
}
public function accelerate($amount) {
$this->speed += $amount;
echo "{$this->brand} 加速到 {$this->speed} km/h\n";
}
public function getBrand() {
return $this->brand;
}
public function getSpeed() {
return $this->speed;
}
}
// 子类(派生类)
class Car extends Vehicle {
private $fuelType;
private $doors;
public function __construct($brand, $fuelType, $doors = 4) {
parent::__construct($brand); // 调用父类构造函数
$this->fuelType = $fuelType;
$this->doors = $doors;
}
// 重写父类方法
public function start() {
echo "{$this->brand} 汽车点火启动\n";
$this->checkFuel();
}
// 新增方法
public function honk() {
echo "{$this->brand} 汽车鸣笛:嘟嘟!\n";
}
private function checkFuel() {
echo "检查{$this->fuelType}燃料\n";
}
public function getInfo() {
return "品牌: {$this->brand}, 燃料: {$this->fuelType}, 车门: {$this->doors}";
}
}
// 使用示例
$car = new Car("丰田", "汽油");
$car->start();
$car->accelerate(50);
$car->honk();
echo $car->getInfo() . "\n";
?>方法重写和parent关键字
php
<?php
class Animal {
protected $name;
protected $age;
public function __construct($name, $age) {
$this->name = $name;
$this->age = $age;
}
public function makeSound() {
echo "{$this->name} 发出声音\n";
}
public function eat($food) {
echo "{$this->name} 正在吃 {$food}\n";
}
public function getInfo() {
return "姓名: {$this->name}, 年龄: {$this->age}";
}
}
class Dog extends Animal {
private $breed;
public function __construct($name, $age, $breed) {
parent::__construct($name, $age);
$this->breed = $breed;
}
// 重写父类方法
public function makeSound() {
echo "{$this->name} 汪汪叫\n";
}
// 重写并扩展父类方法
public function eat($food) {
parent::eat($food); // 调用父类方法
echo "{$this->name} 摇尾巴表示满意\n";
}
// 重写父类方法
public function getInfo() {
return parent::getInfo() . ", 品种: {$this->breed}";
}
// 新增方法
public function fetch() {
echo "{$this->name} 去捡球\n";
}
}
class Cat extends Animal {
private $color;
public function __construct($name, $age, $color) {
parent::__construct($name, $age);
$this->color = $color;
}
public function makeSound() {
echo "{$this->name} 喵喵叫\n";
}
public function climb() {
echo "{$this->name} 爬树\n";
}
public function getInfo() {
return parent::getInfo() . ", 颜色: {$this->color}";
}
}
// 使用示例
$dog = new Dog("小白", 3, "金毛");
$cat = new Cat("小花", 2, "橘色");
$dog->makeSound();
$dog->eat("狗粮");
$dog->fetch();
echo $dog->getInfo() . "\n";
$cat->makeSound();
$cat->eat("猫粮");
$cat->climb();
echo $cat->getInfo() . "\n";
?>抽象类
抽象类基础
php
<?php
// 抽象类不能被直接实例化
abstract class Shape {
protected $color;
public function __construct($color) {
$this->color = $color;
}
// 具体方法
public function getColor() {
return $this->color;
}
// 抽象方法必须在子类中实现
abstract public function calculateArea();
abstract public function calculatePerimeter();
// 模板方法模式
public function displayInfo() {
echo "颜色: {$this->color}\n";
echo "面积: " . $this->calculateArea() . "\n";
echo "周长: " . $this->calculatePerimeter() . "\n";
}
}
class Circle extends Shape {
private $radius;
public function __construct($color, $radius) {
parent::__construct($color);
$this->radius = $radius;
}
public function calculateArea() {
return pi() * $this->radius * $this->radius;
}
public function calculatePerimeter() {
return 2 * pi() * $this->radius;
}
}
class Rectangle extends Shape {
private $width;
private $height;
public function __construct($color, $width, $height) {
parent::__construct($color);
$this->width = $width;
$this->height = $height;
}
public function calculateArea() {
return $this->width * $this->height;
}
public function calculatePerimeter() {
return 2 * ($this->width + $this->height);
}
}
// 使用示例
$circle = new Circle("红色", 5);
$rectangle = new Rectangle("蓝色", 10, 6);
$circle->displayInfo();
echo "---\n";
$rectangle->displayInfo();
?>抽象类的实际应用
php
<?php
abstract class DatabaseConnection {
protected $host;
protected $database;
protected $username;
protected $password;
protected $connection;
public function __construct($host, $database, $username, $password) {
$this->host = $host;
$this->database = $database;
$this->username = $username;
$this->password = $password;
}
// 抽象方法
abstract protected function connect();
abstract public function query($sql);
abstract public function close();
// 具体方法
public function isConnected() {
return $this->connection !== null;
}
public function getDatabaseName() {
return $this->database;
}
}
class MySQLConnection extends DatabaseConnection {
protected function connect() {
$this->connection = new PDO(
"mysql:host={$this->host};dbname={$this->database}",
$this->username,
$this->password
);
$this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
public function query($sql) {
if (!$this->isConnected()) {
$this->connect();
}
return $this->connection->query($sql);
}
public function close() {
$this->connection = null;
}
}
class PostgreSQLConnection extends DatabaseConnection {
protected function connect() {
$this->connection = new PDO(
"pgsql:host={$this->host};dbname={$this->database}",
$this->username,
$this->password
);
$this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
public function query($sql) {
if (!$this->isConnected()) {
$this->connect();
}
return $this->connection->query($sql);
}
public function close() {
$this->connection = null;
}
}
?>接口
接口基础
php
<?php
// 定义接口
interface Flyable {
public function fly();
public function land();
}
interface Swimmable {
public function swim();
public function dive();
}
// 一个类可以实现多个接口
class Duck implements Flyable, Swimmable {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function fly() {
echo "{$this->name} 在天空中飞翔\n";
}
public function land() {
echo "{$this->name} 降落到地面\n";
}
public function swim() {
echo "{$this->name} 在水中游泳\n";
}
public function dive() {
echo "{$this->name} 潜入水中\n";
}
public function quack() {
echo "{$this->name} 嘎嘎叫\n";
}
}
class Airplane implements Flyable {
private $model;
public function __construct($model) {
$this->model = $model;
}
public function fly() {
echo "{$this->model} 飞机在高空飞行\n";
}
public function land() {
echo "{$this->model} 飞机降落在跑道上\n";
}
}
// 使用示例
$duck = new Duck("唐老鸭");
$plane = new Airplane("波音747");
$duck->fly();
$duck->swim();
$duck->quack();
$plane->fly();
$plane->land();
?>接口继承
php
<?php
interface Readable {
public function read();
}
interface Writable {
public function write($data);
}
// 接口可以继承其他接口
interface ReadWritable extends Readable, Writable {
public function isReadOnly();
}
class File implements ReadWritable {
private $filename;
private $readOnly;
public function __construct($filename, $readOnly = false) {
$this->filename = $filename;
$this->readOnly = $readOnly;
}
public function read() {
if (file_exists($this->filename)) {
return file_get_contents($this->filename);
}
return false;
}
public function write($data) {
if ($this->readOnly) {
throw new Exception("文件是只读的");
}
return file_put_contents($this->filename, $data);
}
public function isReadOnly() {
return $this->readOnly;
}
}
// 使用示例
$file = new File("data.txt");
$file->write("Hello, World!");
echo $file->read();
echo "只读模式: " . ($file->isReadOnly() ? "是" : "否") . "\n";
?>Trait
Trait基础
php
<?php
// 定义Trait
trait Loggable {
private $logFile = 'app.log';
public function log($message) {
$timestamp = date('Y-m-d H:i:s');
$logEntry = "[$timestamp] $message\n";
file_put_contents($this->logFile, $logEntry, FILE_APPEND);
}
public function setLogFile($filename) {
$this->logFile = $filename;
}
}
trait Cacheable {
private $cache = [];
public function getFromCache($key) {
return $this->cache[$key] ?? null;
}
public function putInCache($key, $value) {
$this->cache[$key] = $value;
}
public function clearCache() {
$this->cache = [];
}
}
// 使用Trait
class UserService {
use Loggable, Cacheable;
public function getUser($id) {
// 先检查缓存
$user = $this->getFromCache("user_$id");
if ($user !== null) {
$this->log("从缓存获取用户 $id");
return $user;
}
// 模拟从数据库获取
$user = "用户数据_$id";
$this->putInCache("user_$id", $user);
$this->log("从数据库获取用户 $id");
return $user;
}
public function updateUser($id, $data) {
// 更新逻辑
$this->log("更新用户 $id: $data");
// 清除缓存
$this->clearCache();
}
}
$userService = new UserService();
$userService->setLogFile('user_service.log');
echo $userService->getUser(1) . "\n";
echo $userService->getUser(1) . "\n"; // 从缓存获取
$userService->updateUser(1, "新数据");
?>Trait冲突解决
php
<?php
trait TraitA {
public function hello() {
echo "Hello from TraitA\n";
}
public function goodbye() {
echo "Goodbye from TraitA\n";
}
}
trait TraitB {
public function hello() {
echo "Hello from TraitB\n";
}
public function welcome() {
echo "Welcome from TraitB\n";
}
}
class MyClass {
use TraitA, TraitB {
TraitB::hello insteadof TraitA; // 使用TraitB的hello方法
TraitA::hello as helloA; // 给TraitA的hello方法起别名
TraitA::goodbye as private goodbyePrivate; // 修改访问修饰符
}
}
$obj = new MyClass();
$obj->hello(); // 输出: Hello from TraitB
$obj->helloA(); // 输出: Hello from TraitA
$obj->goodbye(); // 输出: Goodbye from TraitA
$obj->welcome(); // 输出: Welcome from TraitB
// $obj->goodbyePrivate(); // 错误,因为是private的
?>Trait组合和继承
php
<?php
trait Timestampable {
private $createdAt;
private $updatedAt;
public function setCreatedAt($timestamp = null) {
$this->createdAt = $timestamp ?? time();
}
public function setUpdatedAt($timestamp = null) {
$this->updatedAt = $timestamp ?? time();
}
public function getCreatedAt() {
return $this->createdAt;
}
public function getUpdatedAt() {
return $this->updatedAt;
}
}
trait Validatable {
private $errors = [];
abstract protected function getRules();
public function validate($data) {
$this->errors = [];
$rules = $this->getRules();
foreach ($rules as $field => $rule) {
if (!isset($data[$field])) {
$this->errors[$field] = "字段 $field 是必需的";
continue;
}
if ($rule === 'required' && empty($data[$field])) {
$this->errors[$field] = "字段 $field 不能为空";
}
}
return empty($this->errors);
}
public function getErrors() {
return $this->errors;
}
}
// Trait可以使用其他Trait
trait ActiveRecord {
use Timestampable, Validatable;
public function save() {
if (!$this->validate($this->toArray())) {
throw new Exception("验证失败: " . implode(', ', $this->getErrors()));
}
if ($this->createdAt === null) {
$this->setCreatedAt();
}
$this->setUpdatedAt();
// 保存到数据库的逻辑
echo "记录已保存\n";
}
abstract public function toArray();
}
class User {
use ActiveRecord;
private $name;
private $email;
public function __construct($name, $email) {
$this->name = $name;
$this->email = $email;
}
protected function getRules() {
return [
'name' => 'required',
'email' => 'required'
];
}
public function toArray() {
return [
'name' => $this->name,
'email' => $this->email
];
}
}
// 使用示例
$user = new User("张三", "zhang@example.com");
$user->save();
echo "创建时间: " . date('Y-m-d H:i:s', $user->getCreatedAt()) . "\n";
echo "更新时间: " . date('Y-m-d H:i:s', $user->getUpdatedAt()) . "\n";
?>多态性
多态性示例
php
<?php
interface PaymentProcessor {
public function processPayment($amount);
public function getProcessorName();
}
class CreditCardProcessor implements PaymentProcessor {
private $cardNumber;
public function __construct($cardNumber) {
$this->cardNumber = $cardNumber;
}
public function processPayment($amount) {
echo "使用信用卡处理 $amount 元支付\n";
echo "卡号: ****" . substr($this->cardNumber, -4) . "\n";
return true;
}
public function getProcessorName() {
return "信用卡处理器";
}
}
class PayPalProcessor implements PaymentProcessor {
private $email;
public function __construct($email) {
$this->email = $email;
}
public function processPayment($amount) {
echo "使用PayPal处理 $amount 元支付\n";
echo "PayPal账户: {$this->email}\n";
return true;
}
public function getProcessorName() {
return "PayPal处理器";
}
}
class WeChatPayProcessor implements PaymentProcessor {
private $phoneNumber;
public function __construct($phoneNumber) {
$this->phoneNumber = $phoneNumber;
}
public function processPayment($amount) {
echo "使用微信支付处理 $amount 元支付\n";
echo "手机号: {$this->phoneNumber}\n";
return true;
}
public function getProcessorName() {
return "微信支付处理器";
}
}
// 支付管理器
class PaymentManager {
public function processPayment(PaymentProcessor $processor, $amount) {
echo "正在使用 " . $processor->getProcessorName() . " 处理支付...\n";
$result = $processor->processPayment($amount);
if ($result) {
echo "支付成功!\n";
} else {
echo "支付失败!\n";
}
echo "---\n";
}
}
// 使用示例(多态性体现)
$paymentManager = new PaymentManager();
$processors = [
new CreditCardProcessor("1234567890123456"),
new PayPalProcessor("user@example.com"),
new WeChatPayProcessor("13800138000")
];
foreach ($processors as $processor) {
$paymentManager->processPayment($processor, 100);
}
?>最佳实践
1. 继承vs组合
php
<?php
// 不好的继承设计
class Bird {
public function fly() {
echo "飞行\n";
}
}
class Penguin extends Bird {
public function fly() {
throw new Exception("企鹅不能飞行");
}
}
// 更好的设计:使用组合和接口
interface Flyable {
public function fly();
}
interface Swimmable {
public function swim();
}
class FlyingBehavior implements Flyable {
public function fly() {
echo "在天空中飞翔\n";
}
}
class SwimmingBehavior implements Swimmable {
public function swim() {
echo "在水中游泳\n";
}
}
abstract class Bird {
protected $name;
public function __construct($name) {
$this->name = $name;
}
public function eat() {
echo "{$this->name} 正在吃东西\n";
}
}
class Eagle extends Bird implements Flyable {
private $flyingBehavior;
public function __construct($name) {
parent::__construct($name);
$this->flyingBehavior = new FlyingBehavior();
}
public function fly() {
echo "{$this->name} ";
$this->flyingBehavior->fly();
}
}
class Penguin extends Bird implements Swimmable {
private $swimmingBehavior;
public function __construct($name) {
parent::__construct($name);
$this->swimmingBehavior = new SwimmingBehavior();
}
public function swim() {
echo "{$this->name} ";
$this->swimmingBehavior->swim();
}
}
?>2. 接口分离原则
php
<?php
// 不好的接口设计(接口过大)
interface Worker {
public function work();
public function eat();
public function sleep();
public function writeCode();
public function designUI();
}
// 更好的设计:分离接口
interface Workable {
public function work();
}
interface Eatable {
public function eat();
}
interface Sleepable {
public function sleep();
}
interface Programmable {
public function writeCode();
}
interface Designable {
public function designUI();
}
class Developer implements Workable, Eatable, Sleepable, Programmable {
public function work() {
echo "开发者正在工作\n";
}
public function eat() {
echo "开发者正在吃饭\n";
}
public function sleep() {
echo "开发者正在睡觉\n";
}
public function writeCode() {
echo "开发者正在写代码\n";
}
}
class Designer implements Workable, Eatable, Sleepable, Designable {
public function work() {
echo "设计师正在工作\n";
}
public function eat() {
echo "设计师正在吃饭\n";
}
public function sleep() {
echo "设计师正在睡觉\n";
}
public function designUI() {
echo "设计师正在设计UI\n";
}
}
?>总结
本章介绍了PHP中的继承和Trait机制:
- 类继承:通过extends关键字实现单继承,使用parent::访问父类
- 抽象类:定义抽象方法,为子类提供通用接口和部分实现
- 接口:定义契约,类可以实现多个接口
- Trait:实现代码复用,解决单继承的局限性
- 多态性:通过接口实现,允许不同类以统一方式处理
合理使用这些特性可以构建灵活、可维护的面向对象应用程序。在下一章中,我们将学习PHP中的正则表达式。