Skip to content

继承和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中的正则表达式。

本站内容仅供学习和研究使用。