面向对象编程(OOP)是PHP的核心特性之一,它提供了封装、继承和多态等重要概念。本章将详细介绍PHP中的类和对象、属性和方法、继承、接口、抽象类、命名空间等面向对象编程的核心内容。

7.1 类和对象基础

7.1.1 类的定义和实例化

<?php
// 基本类定义
class User {
    // 属性(成员变量)
    public $name;
    public $email;
    private $password;
    protected $id;
    
    // 构造函数
    public function __construct($name, $email, $password) {
        $this->name = $name;
        $this->email = $email;
        $this->password = password_hash($password, PASSWORD_DEFAULT);
        $this->id = uniqid();
    }
    
    // 方法(成员函数)
    public function getName() {
        return $this->name;
    }
    
    public function setName($name) {
        if (strlen($name) >= 2) {
            $this->name = $name;
            return true;
        }
        return false;
    }
    
    public function getEmail() {
        return $this->email;
    }
    
    public function verifyPassword($password) {
        return password_verify($password, $this->password);
    }
    
    // 受保护的方法
    protected function getId() {
        return $this->id;
    }
    
    // 私有方法
    private function hashPassword($password) {
        return password_hash($password, PASSWORD_DEFAULT);
    }
}

// 创建对象实例
$user1 = new User("张三", "zhangsan@example.com", "password123");
$user2 = new User("李四", "lisi@example.com", "mypassword");

echo "用户1姓名:" . $user1->getName() . "\n";
echo "用户1邮箱:" . $user1->getEmail() . "\n";
echo "密码验证:" . ($user1->verifyPassword("password123") ? "正确" : "错误") . "\n";

// 修改属性
$user1->setName("张三丰");
echo "修改后姓名:" . $user1->getName() . "\n";

// 直接访问公共属性
$user1->name = "张无忌";
echo "直接修改后姓名:" . $user1->name . "\n";
?>

7.1.2 访问修饰符

<?php
class AccessModifierDemo {
    public $publicProperty = "公共属性";
    protected $protectedProperty = "受保护属性";
    private $privateProperty = "私有属性";
    
    public function publicMethod() {
        echo "公共方法\n";
        echo "访问公共属性:" . $this->publicProperty . "\n";
        echo "访问受保护属性:" . $this->protectedProperty . "\n";
        echo "访问私有属性:" . $this->privateProperty . "\n";
    }
    
    protected function protectedMethod() {
        echo "受保护方法\n";
    }
    
    private function privateMethod() {
        echo "私有方法\n";
    }
    
    public function callAllMethods() {
        $this->publicMethod();
        $this->protectedMethod();
        $this->privateMethod();
    }
}

class ChildClass extends AccessModifierDemo {
    public function accessParentProperties() {
        echo "子类访问父类属性:\n";
        echo "公共属性:" . $this->publicProperty . "\n";
        echo "受保护属性:" . $this->protectedProperty . "\n";
        // echo $this->privateProperty; // 错误:无法访问私有属性
    }
    
    public function callParentMethods() {
        echo "子类调用父类方法:\n";
        $this->publicMethod();
        $this->protectedMethod();
        // $this->privateMethod(); // 错误:无法访问私有方法
    }
}

$demo = new AccessModifierDemo();
echo "=== 基类测试 ===\n";
$demo->callAllMethods();

echo "\n=== 子类测试 ===\n";
$child = new ChildClass();
$child->accessParentProperties();
$child->callParentMethods();

// 外部访问测试
echo "\n=== 外部访问测试 ===\n";
echo "公共属性:" . $demo->publicProperty . "\n";
// echo $demo->protectedProperty; // 错误:无法访问受保护属性
// echo $demo->privateProperty;   // 错误:无法访问私有属性
?>

7.1.3 魔术方法

<?php
class MagicMethodsDemo {
    private $data = [];
    
    // 构造函数
    public function __construct($initialData = []) {
        $this->data = $initialData;
        echo "对象被创建\n";
    }
    
    // 析构函数
    public function __destruct() {
        echo "对象被销毁\n";
    }
    
    // 获取不存在的属性时调用
    public function __get($name) {
        echo "尝试获取属性:$name\n";
        return isset($this->data[$name]) ? $this->data[$name] : null;
    }
    
    // 设置不存在的属性时调用
    public function __set($name, $value) {
        echo "设置属性:$name = $value\n";
        $this->data[$name] = $value;
    }
    
    // 检查属性是否存在时调用
    public function __isset($name) {
        echo "检查属性是否存在:$name\n";
        return isset($this->data[$name]);
    }
    
    // 删除属性时调用
    public function __unset($name) {
        echo "删除属性:$name\n";
        unset($this->data[$name]);
    }
    
    // 调用不存在的方法时调用
    public function __call($name, $arguments) {
        echo "调用不存在的方法:$name,参数:" . implode(', ', $arguments) . "\n";
        return "方法 $name 不存在";
    }
    
    // 静态调用不存在的方法时调用
    public static function __callStatic($name, $arguments) {
        echo "静态调用不存在的方法:$name,参数:" . implode(', ', $arguments) . "\n";
        return "静态方法 $name 不存在";
    }
    
    // 对象被当作字符串使用时调用
    public function __toString() {
        return "MagicMethodsDemo对象,数据:" . json_encode($this->data);
    }
    
    // 对象被当作函数调用时调用
    public function __invoke($param) {
        echo "对象被当作函数调用,参数:$param\n";
        return "调用结果:$param";
    }
    
    // 对象被克隆时调用
    public function __clone() {
        echo "对象被克隆\n";
        // 深拷贝数据
        $this->data = array_merge([], $this->data);
    }
    
    // 序列化时调用
    public function __sleep() {
        echo "对象被序列化\n";
        return ['data']; // 返回需要序列化的属性名数组
    }
    
    // 反序列化时调用
    public function __wakeup() {
        echo "对象被反序列化\n";
    }
}

echo "=== 魔术方法演示 ===\n";
$obj = new MagicMethodsDemo(['name' => '张三', 'age' => 25]);

// __get 和 __set
echo "姓名:" . $obj->name . "\n";
$obj->email = "zhangsan@example.com";

// __isset 和 __unset
var_dump(isset($obj->name));
unset($obj->age);

// __call
$obj->nonExistentMethod('参数1', '参数2');

// __callStatic
MagicMethodsDemo::nonExistentStaticMethod('静态参数');

// __toString
echo "对象字符串表示:" . $obj . "\n";

// __invoke
echo $obj('调用参数') . "\n";

// __clone
$clonedObj = clone $obj;

// 序列化和反序列化
$serialized = serialize($obj);
$unserialized = unserialize($serialized);

echo "\n=== 对象生命周期结束 ===\n";
?>

7.2 继承和多态

7.2.1 类的继承

<?php
// 基类(父类)
class Animal {
    protected $name;
    protected $species;
    protected $age;
    
    public function __construct($name, $species, $age = 0) {
        $this->name = $name;
        $this->species = $species;
        $this->age = $age;
    }
    
    public function getName() {
        return $this->name;
    }
    
    public function getSpecies() {
        return $this->species;
    }
    
    public function getAge() {
        return $this->age;
    }
    
    public function makeSound() {
        return "动物发出声音";
    }
    
    public function move() {
        return "{$this->name}在移动";
    }
    
    public function getInfo() {
        return "姓名:{$this->name},种类:{$this->species},年龄:{$this->age}";
    }
}

// 派生类(子类)
class Dog extends Animal {
    private $breed;
    
    public function __construct($name, $age = 0, $breed = '未知') {
        parent::__construct($name, '犬类', $age);
        $this->breed = $breed;
    }
    
    public function getBreed() {
        return $this->breed;
    }
    
    // 重写父类方法
    public function makeSound() {
        return "{$this->name}汪汪叫";
    }
    
    public function move() {
        return "{$this->name}跑来跑去";
    }
    
    // 新增方法
    public function fetch() {
        return "{$this->name}去捡球";
    }
    
    public function wagTail() {
        return "{$this->name}摇尾巴";
    }
    
    // 重写getInfo方法
    public function getInfo() {
        return parent::getInfo() . ",品种:{$this->breed}";
    }
}

class Cat extends Animal {
    private $isIndoor;
    
    public function __construct($name, $age = 0, $isIndoor = true) {
        parent::__construct($name, '猫类', $age);
        $this->isIndoor = $isIndoor;
    }
    
    public function isIndoorCat() {
        return $this->isIndoor;
    }
    
    // 重写父类方法
    public function makeSound() {
        return "{$this->name}喵喵叫";
    }
    
    public function move() {
        return "{$this->name}优雅地走动";
    }
    
    // 新增方法
    public function purr() {
        return "{$this->name}发出呼噜声";
    }
    
    public function climb() {
        return "{$this->name}爬树";
    }
    
    public function getInfo() {
        $location = $this->isIndoor ? '室内' : '室外';
        return parent::getInfo() . ",生活环境:{$location}";
    }
}

// 使用继承
echo "=== 继承演示 ===\n";

$animal = new Animal('通用动物', '未知种类', 5);
$dog = new Dog('旺财', 3, '金毛');
$cat = new Cat('咪咪', 2, true);

echo "基类动物:\n";
echo $animal->getInfo() . "\n";
echo $animal->makeSound() . "\n";
echo $animal->move() . "\n\n";

echo "狗类:\n";
echo $dog->getInfo() . "\n";
echo $dog->makeSound() . "\n";
echo $dog->move() . "\n";
echo $dog->fetch() . "\n";
echo $dog->wagTail() . "\n\n";

echo "猫类:\n";
echo $cat->getInfo() . "\n";
echo $cat->makeSound() . "\n";
echo $cat->move() . "\n";
echo $cat->purr() . "\n";
echo $cat->climb() . "\n";
?>

7.2.2 多态性

<?php
// 多态演示
function animalConcert($animals) {
    echo "=== 动物音乐会 ===\n";
    foreach ($animals as $animal) {
        echo $animal->getName() . ":" . $animal->makeSound() . "\n";
    }
}

function animalSports($animals) {
    echo "\n=== 动物运动会 ===\n";
    foreach ($animals as $animal) {
        echo $animal->move() . "\n";
    }
}

// 创建不同类型的动物
$animals = [
    new Dog('旺财', 3, '金毛'),
    new Cat('咪咪', 2, true),
    new Dog('小黑', 1, '拉布拉多'),
    new Cat('橘猫', 4, false),
    new Animal('鹦鹉', '鸟类', 1)
];

// 多态调用 - 同样的方法调用,不同的行为
animalConcert($animals);
animalSports($animals);

// 类型检查
echo "\n=== 类型检查 ===\n";
foreach ($animals as $animal) {
    echo $animal->getName() . " 是 ";
    
    if ($animal instanceof Dog) {
        echo "狗类,品种:" . $animal->getBreed() . "\n";
    } elseif ($animal instanceof Cat) {
        echo "猫类," . ($animal->isIndoorCat() ? "室内猫" : "室外猫") . "\n";
    } else {
        echo "基础动物类\n";
    }
}

// 方法存在性检查
echo "\n=== 方法检查 ===\n";
foreach ($animals as $animal) {
    echo $animal->getName() . ":";
    
    if (method_exists($animal, 'fetch')) {
        echo $animal->fetch() . "\n";
    } elseif (method_exists($animal, 'purr')) {
        echo $animal->purr() . "\n";
    } else {
        echo "没有特殊技能\n";
    }
}
?>

7.3 抽象类和接口

7.3.1 抽象类

<?php
// 抽象类
abstract class Shape {
    protected $color;
    protected $name;
    
    public function __construct($color, $name) {
        $this->color = $color;
        $this->name = $name;
    }
    
    // 具体方法
    public function getColor() {
        return $this->color;
    }
    
    public function getName() {
        return $this->name;
    }
    
    public function getInfo() {
        return "形状:{$this->name},颜色:{$this->color}";
    }
    
    // 抽象方法 - 子类必须实现
    abstract public function calculateArea();
    abstract public function calculatePerimeter();
    abstract public function draw();
}

// 具体实现类
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);
    }
    
    public function draw() {
        return "绘制{$this->color}的矩形,宽度:{$this->width},高度:{$this->height}";
    }
    
    public function getWidth() {
        return $this->width;
    }
    
    public function getHeight() {
        return $this->height;
    }
}

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;
    }
    
    public function draw() {
        return "绘制{$this->color}的圆形,半径:{$this->radius}";
    }
    
    public function getRadius() {
        return $this->radius;
    }
}

class Triangle extends Shape {
    private $side1, $side2, $side3;
    
    public function __construct($color, $side1, $side2, $side3) {
        parent::__construct($color, '三角形');
        $this->side1 = $side1;
        $this->side2 = $side2;
        $this->side3 = $side3;
    }
    
    public function calculateArea() {
        // 使用海伦公式
        $s = $this->calculatePerimeter() / 2;
        return sqrt($s * ($s - $this->side1) * ($s - $this->side2) * ($s - $this->side3));
    }
    
    public function calculatePerimeter() {
        return $this->side1 + $this->side2 + $this->side3;
    }
    
    public function draw() {
        return "绘制{$this->color}的三角形,边长:{$this->side1}, {$this->side2}, {$this->side3}";
    }
}

// 使用抽象类
echo "=== 抽象类演示 ===\n";

$shapes = [
    new Rectangle('红色', 10, 5),
    new Circle('蓝色', 7),
    new Triangle('绿色', 3, 4, 5)
];

foreach ($shapes as $shape) {
    echo $shape->getInfo() . "\n";
    echo "面积:" . number_format($shape->calculateArea(), 2) . "\n";
    echo "周长:" . number_format($shape->calculatePerimeter(), 2) . "\n";
    echo $shape->draw() . "\n\n";
}

// 计算总面积
$totalArea = 0;
foreach ($shapes as $shape) {
    $totalArea += $shape->calculateArea();
}
echo "所有形状的总面积:" . number_format($totalArea, 2) . "\n";
?>

7.3.2 接口

<?php
// 接口定义
interface Drawable {
    public function draw();
    public function getDrawingInfo();
}

interface Movable {
    public function move($x, $y);
    public function getPosition();
}

interface Resizable {
    public function resize($factor);
    public function getSize();
}

// 实现多个接口的类
class GraphicElement implements Drawable, Movable, Resizable {
    private $x, $y;
    private $width, $height;
    private $color;
    private $type;
    
    public function __construct($type, $color, $x = 0, $y = 0, $width = 100, $height = 100) {
        $this->type = $type;
        $this->color = $color;
        $this->x = $x;
        $this->y = $y;
        $this->width = $width;
        $this->height = $height;
    }
    
    // 实现Drawable接口
    public function draw() {
        return "在位置({$this->x}, {$this->y})绘制{$this->color}的{$this->type}";
    }
    
    public function getDrawingInfo() {
        return [
            'type' => $this->type,
            'color' => $this->color,
            'position' => [$this->x, $this->y],
            'size' => [$this->width, $this->height]
        ];
    }
    
    // 实现Movable接口
    public function move($x, $y) {
        $this->x += $x;
        $this->y += $y;
        return "移动到位置({$this->x}, {$this->y})";
    }
    
    public function getPosition() {
        return ['x' => $this->x, 'y' => $this->y];
    }
    
    // 实现Resizable接口
    public function resize($factor) {
        $this->width *= $factor;
        $this->height *= $factor;
        return "调整大小,新尺寸:{$this->width} x {$this->height}";
    }
    
    public function getSize() {
        return ['width' => $this->width, 'height' => $this->height];
    }
}

// 只实现部分接口的类
class StaticImage implements Drawable {
    private $filename;
    private $alt;
    
    public function __construct($filename, $alt = '') {
        $this->filename = $filename;
        $this->alt = $alt;
    }
    
    public function draw() {
        return "显示图片:{$this->filename}";
    }
    
    public function getDrawingInfo() {
        return [
            'type' => 'image',
            'filename' => $this->filename,
            'alt' => $this->alt
        ];
    }
}

// 接口继承
interface AdvancedDrawable extends Drawable {
    public function drawWithEffects($effects);
    public function getLayerInfo();
}

class AdvancedGraphic implements AdvancedDrawable, Movable {
    private $x, $y;
    private $layer;
    private $effects;
    
    public function __construct($x = 0, $y = 0, $layer = 1) {
        $this->x = $x;
        $this->y = $y;
        $this->layer = $layer;
        $this->effects = [];
    }
    
    public function draw() {
        return "在图层{$this->layer}绘制高级图形";
    }
    
    public function getDrawingInfo() {
        return [
            'type' => 'advanced_graphic',
            'layer' => $this->layer,
            'position' => [$this->x, $this->y],
            'effects' => $this->effects
        ];
    }
    
    public function drawWithEffects($effects) {
        $this->effects = $effects;
        return "应用效果:" . implode(', ', $effects) . " 并绘制";
    }
    
    public function getLayerInfo() {
        return ['layer' => $this->layer, 'effects_count' => count($this->effects)];
    }
    
    public function move($x, $y) {
        $this->x += $x;
        $this->y += $y;
        return "高级图形移动到({$this->x}, {$this->y})";
    }
    
    public function getPosition() {
        return ['x' => $this->x, 'y' => $this->y];
    }
}

// 使用接口
echo "=== 接口演示 ===\n";

$elements = [
    new GraphicElement('矩形', '红色', 10, 20, 100, 50),
    new StaticImage('logo.png', '公司标志'),
    new AdvancedGraphic(50, 100, 2)
];

// 多态调用 - 所有元素都实现了Drawable接口
foreach ($elements as $element) {
    echo $element->draw() . "\n";
    print_r($element->getDrawingInfo());
    echo "\n";
}

// 类型检查和特定接口调用
echo "=== 接口类型检查 ===\n";
foreach ($elements as $element) {
    if ($element instanceof Movable) {
        echo $element->move(5, 5) . "\n";
        print_r($element->getPosition());
    }
    
    if ($element instanceof Resizable) {
        echo $element->resize(1.5) . "\n";
        print_r($element->getSize());
    }
    
    if ($element instanceof AdvancedDrawable) {
        echo $element->drawWithEffects(['阴影', '发光', '模糊']) . "\n";
        print_r($element->getLayerInfo());
    }
    
    echo "\n";
}
?>

7.4 特性(Traits)

7.4.1 Trait基础

<?php
// 定义Trait
trait Loggable {
    private $logs = [];
    
    public function log($message, $level = 'INFO') {
        $timestamp = date('Y-m-d H:i:s');
        $this->logs[] = "[$timestamp] [$level] $message";
    }
    
    public function getLogs() {
        return $this->logs;
    }
    
    public function clearLogs() {
        $this->logs = [];
    }
    
    public function getLastLog() {
        return end($this->logs);
    }
}

trait Timestampable {
    private $createdAt;
    private $updatedAt;
    
    public function initTimestamps() {
        $this->createdAt = new DateTime();
        $this->updatedAt = new DateTime();
    }
    
    public function updateTimestamp() {
        $this->updatedAt = new DateTime();
    }
    
    public function getCreatedAt() {
        return $this->createdAt;
    }
    
    public function getUpdatedAt() {
        return $this->updatedAt;
    }
    
    public function getAge() {
        if (!$this->createdAt) {
            return null;
        }
        return $this->createdAt->diff(new DateTime())->format('%a 天');
    }
}

trait Cacheable {
    private $cache = [];
    private $cacheEnabled = true;
    
    public function enableCache() {
        $this->cacheEnabled = true;
    }
    
    public function disableCache() {
        $this->cacheEnabled = false;
        $this->clearCache();
    }
    
    public function cacheGet($key) {
        if (!$this->cacheEnabled) {
            return null;
        }
        return isset($this->cache[$key]) ? $this->cache[$key] : null;
    }
    
    public function cacheSet($key, $value, $ttl = 3600) {
        if (!$this->cacheEnabled) {
            return;
        }
        $this->cache[$key] = [
            'value' => $value,
            'expires' => time() + $ttl
        ];
    }
    
    public function clearCache() {
        $this->cache = [];
    }
    
    private function isExpired($key) {
        return isset($this->cache[$key]) && $this->cache[$key]['expires'] < time();
    }
}

// 使用多个Trait的类
class Article {
    use Loggable, Timestampable, Cacheable;
    
    private $title;
    private $content;
    private $author;
    
    public function __construct($title, $content, $author) {
        $this->title = $title;
        $this->content = $content;
        $this->author = $author;
        
        $this->initTimestamps();
        $this->log("文章创建:$title");
    }
    
    public function getTitle() {
        return $this->title;
    }
    
    public function setTitle($title) {
        $oldTitle = $this->title;
        $this->title = $title;
        $this->updateTimestamp();
        $this->log("标题修改:$oldTitle -> $title");
    }
    
    public function getContent() {
        // 尝试从缓存获取
        $cached = $this->cacheGet('content');
        if ($cached !== null) {
            $this->log("从缓存获取内容");
            return $cached['value'];
        }
        
        // 模拟复杂的内容处理
        $processedContent = $this->processContent($this->content);
        $this->cacheSet('content', $processedContent);
        $this->log("内容处理完成并缓存");
        
        return $processedContent;
    }
    
    public function setContent($content) {
        $this->content = $content;
        $this->updateTimestamp();
        $this->clearCache(); // 清除缓存
        $this->log("内容已更新");
    }
    
    public function getAuthor() {
        return $this->author;
    }
    
    private function processContent($content) {
        // 模拟内容处理(如Markdown转换等)
        return strtoupper($content); // 简单示例
    }
    
    public function getInfo() {
        return [
            'title' => $this->title,
            'author' => $this->author,
            'created' => $this->getCreatedAt()->format('Y-m-d H:i:s'),
            'updated' => $this->getUpdatedAt()->format('Y-m-d H:i:s'),
            'age' => $this->getAge()
        ];
    }
}

// 使用示例
echo "=== Trait演示 ===\n";

$article = new Article(
    "PHP面向对象编程",
    "这是一篇关于PHP OOP的文章内容...",
    "张三"
);

echo "文章信息:\n";
print_r($article->getInfo());

echo "\n获取内容(第一次):\n";
echo $article->getContent() . "\n";

echo "\n获取内容(第二次,从缓存):\n";
echo $article->getContent() . "\n";

// 修改文章
sleep(1); // 确保时间戳不同
$article->setTitle("PHP高级面向对象编程");
$article->setContent("这是更新后的文章内容...");

echo "\n更新后的文章信息:\n";
print_r($article->getInfo());

echo "\n操作日志:\n";
foreach ($article->getLogs() as $log) {
    echo $log . "\n";
}
?>

7.4.2 Trait冲突解决

<?php
// 定义有冲突方法的Trait
trait TraitA {
    public function commonMethod() {
        return "来自TraitA的方法";
    }
    
    public function methodA() {
        return "TraitA特有方法";
    }
}

trait TraitB {
    public function commonMethod() {
        return "来自TraitB的方法";
    }
    
    public function methodB() {
        return "TraitB特有方法";
    }
}

trait TraitC {
    public function methodC() {
        return "TraitC特有方法";
    }
    
    private function privateMethod() {
        return "TraitC私有方法";
    }
}

// 解决冲突的类
class ConflictResolver {
    use TraitA, TraitB, TraitC {
        // 指定使用TraitA的commonMethod
        TraitA::commonMethod insteadof TraitB;
        // 给TraitB的commonMethod起别名
        TraitB::commonMethod as commonMethodFromB;
        // 修改方法可见性
        TraitC::privateMethod as public publicPrivateMethod;
    }
    
    public function demonstrateResolution() {
        echo "默认commonMethod:" . $this->commonMethod() . "\n";
        echo "TraitB的commonMethod:" . $this->commonMethodFromB() . "\n";
        echo "TraitA特有方法:" . $this->methodA() . "\n";
        echo "TraitB特有方法:" . $this->methodB() . "\n";
        echo "TraitC特有方法:" . $this->methodC() . "\n";
        echo "公开的私有方法:" . $this->publicPrivateMethod() . "\n";
    }
}

// Trait组合
trait CombinedTrait {
    use TraitA, TraitB {
        TraitA::commonMethod insteadof TraitB;
        TraitB::commonMethod as alternativeMethod;
    }
    
    public function getCombinedInfo() {
        return [
            'primary' => $this->commonMethod(),
            'alternative' => $this->alternativeMethod(),
            'methodA' => $this->methodA(),
            'methodB' => $this->methodB()
        ];
    }
}

class UsingCombinedTrait {
    use CombinedTrait;
    
    public function showAll() {
        return $this->getCombinedInfo();
    }
}

// 演示冲突解决
echo "=== Trait冲突解决演示 ===\n";

$resolver = new ConflictResolver();
$resolver->demonstrateResolution();

echo "\n=== 组合Trait演示 ===\n";
$combined = new UsingCombinedTrait();
print_r($combined->showAll());
?>

7.5 命名空间

7.5.1 命名空间基础

<?php
// 文件:User.php
namespace App\Models;

class User {
    private $name;
    private $email;
    
    public function __construct($name, $email) {
        $this->name = $name;
        $this->email = $email;
    }
    
    public function getName() {
        return $this->name;
    }
    
    public function getEmail() {
        return $this->email;
    }
}

// 文件:UserController.php
namespace App\Controllers;

use App\Models\User;
use App\Services\EmailService;
use DateTime;

class UserController {
    private $emailService;
    
    public function __construct() {
        $this->emailService = new EmailService();
    }
    
    public function createUser($name, $email) {
        // 创建用户
        $user = new User($name, $email);
        
        // 发送欢迎邮件
        $this->emailService->sendWelcomeEmail($user);
        
        return $user;
    }
    
    public function getCurrentTime() {
        // 使用全局类
        return new DateTime();
    }
    
    public function getFullClassName() {
        // 获取完全限定类名
        return __NAMESPACE__ . '\\UserController';
    }
}

// 文件:EmailService.php
namespace App\Services;

use App\Models\User;

class EmailService {
    public function sendWelcomeEmail(User $user) {
        return "发送欢迎邮件给:" . $user->getName() . " (" . $user->getEmail() . ")";
    }
    
    public function sendNotification($email, $message) {
        return "发送通知到 $email:$message";
    }
}

// 文件:main.php - 使用命名空间
namespace App;

// 导入需要的类
use App\Controllers\UserController;
use App\Models\User;
use App\Services\EmailService;

// 别名
use App\Controllers\UserController as UC;
use DateTime as DT;

echo "=== 命名空间演示 ===\n";

// 使用完全限定名
$user1 = new \App\Models\User("张三", "zhangsan@example.com");
echo "用户1:" . $user1->getName() . "\n";

// 使用导入的类
$controller = new UserController();
$user2 = $controller->createUser("李四", "lisi@example.com");
echo "用户2:" . $user2->getName() . "\n";

// 使用别名
$controller2 = new UC();
echo "控制器类名:" . $controller2->getFullClassName() . "\n";

// 使用别名的DateTime
$now = new DT();
echo "当前时间:" . $now->format('Y-m-d H:i:s') . "\n";

// 直接使用服务
$emailService = new EmailService();
echo $emailService->sendWelcomeEmail($user1) . "\n";
?>

7.5.2 子命名空间和组织结构

<?php
// 文件结构示例
// App/
//   Models/
//     User.php
//     Product.php
//   Controllers/
//     Web/
//       UserController.php
//       ProductController.php
//     Api/
//       V1/
//         UserController.php
//         ProductController.php
//   Services/
//     Auth/
//       AuthService.php
//       TokenService.php
//     Payment/
//       PayPalService.php
//       StripeService.php

// App/Controllers/Web/UserController.php
namespace App\Controllers\Web;

use App\Models\User;
use App\Services\Auth\AuthService;

class UserController {
    private $authService;
    
    public function __construct() {
        $this->authService = new AuthService();
    }
    
    public function login($email, $password) {
        return $this->authService->authenticate($email, $password);
    }
    
    public function register($userData) {
        $user = new User($userData['name'], $userData['email']);
        return $this->authService->register($user, $userData['password']);
    }
}

// App/Controllers/Api/V1/UserController.php
namespace App\Controllers\Api\V1;

use App\Models\User;
use App\Services\Auth\TokenService;

class UserController {
    private $tokenService;
    
    public function __construct() {
        $this->tokenService = new TokenService();
    }
    
    public function apiLogin($email, $password) {
        // API登录逻辑
        $token = $this->tokenService->generateToken($email);
        return ['token' => $token, 'expires_in' => 3600];
    }
    
    public function getProfile($token) {
        if ($this->tokenService->validateToken($token)) {
            return ['name' => '用户名', 'email' => 'user@example.com'];
        }
        return ['error' => '无效令牌'];
    }
}

// App/Services/Auth/AuthService.php
namespace App\Services\Auth;

use App\Models\User;

class AuthService {
    public function authenticate($email, $password) {
        // 模拟认证逻辑
        if ($email === 'admin@example.com' && $password === 'password') {
            return new User('管理员', $email);
        }
        return false;
    }
    
    public function register(User $user, $password) {
        // 模拟注册逻辑
        return "用户 {$user->getName()} 注册成功";
    }
}

// App/Services/Auth/TokenService.php
namespace App\Services\Auth;

class TokenService {
    private $tokens = [];
    
    public function generateToken($email) {
        $token = bin2hex(random_bytes(32));
        $this->tokens[$token] = [
            'email' => $email,
            'expires' => time() + 3600
        ];
        return $token;
    }
    
    public function validateToken($token) {
        if (isset($this->tokens[$token])) {
            return $this->tokens[$token]['expires'] > time();
        }
        return false;
    }
}

// 使用示例
namespace App;

use App\Controllers\Web\UserController as WebUserController;
use App\Controllers\Api\V1\UserController as ApiUserController;

echo "=== 子命名空间演示 ===\n";

// Web控制器
$webController = new WebUserController();
$webUser = $webController->login('admin@example.com', 'password');
if ($webUser) {
    echo "Web登录成功:" . $webUser->getName() . "\n";
}

// API控制器
$apiController = new ApiUserController();
$apiResponse = $apiController->apiLogin('admin@example.com', 'password');
echo "API登录响应:" . json_encode($apiResponse) . "\n";

$profile = $apiController->getProfile($apiResponse['token']);
echo "用户资料:" . json_encode($profile) . "\n";
?>

7.6 自动加载

7.6.1 PSR-4自动加载

<?php
// 文件:autoload.php
class Autoloader {
    private $prefixes = [];
    
    /**
     * 注册自动加载器
     */
    public function register() {
        spl_autoload_register([$this, 'loadClass']);
    }
    
    /**
     * 添加命名空间前缀
     */
    public function addNamespace($prefix, $baseDir, $prepend = false) {
        // 规范化命名空间前缀
        $prefix = trim($prefix, '\\') . '\\';
        
        // 规范化基础目录
        $baseDir = rtrim($baseDir, DIRECTORY_SEPARATOR) . '/';
        
        // 初始化命名空间前缀数组
        if (isset($this->prefixes[$prefix]) === false) {
            $this->prefixes[$prefix] = [];
        }
        
        // 保留基础目录
        if ($prepend) {
            array_unshift($this->prefixes[$prefix], $baseDir);
        } else {
            array_push($this->prefixes[$prefix], $baseDir);
        }
    }
    
    /**
     * 加载类文件
     */
    public function loadClass($class) {
        // 当前命名空间前缀
        $prefix = $class;
        
        // 从后往前查找命名空间前缀
        while (false !== $pos = strrpos($prefix, '\\')) {
            // 保留命名空间分隔符
            $prefix = substr($class, 0, $pos + 1);
            
            // 剩余的类名
            $relativeClass = substr($class, $pos + 1);
            
            // 尝试加载映射的文件
            $mappedFile = $this->loadMappedFile($prefix, $relativeClass);
            if ($mappedFile) {
                return $mappedFile;
            }
            
            // 移除尾部的命名空间分隔符
            $prefix = rtrim($prefix, '\\');
        }
        
        return false;
    }
    
    /**
     * 加载映射文件
     */
    protected function loadMappedFile($prefix, $relativeClass) {
        // 检查前缀是否有基础目录
        if (isset($this->prefixes[$prefix]) === false) {
            return false;
        }
        
        // 遍历前缀的基础目录
        foreach ($this->prefixes[$prefix] as $baseDir) {
            // 将命名空间分隔符替换为目录分隔符
            $file = $baseDir . str_replace('\\', '/', $relativeClass) . '.php';
            
            // 如果映射文件存在,则加载它
            if ($this->requireFile($file)) {
                return $file;
            }
        }
        
        return false;
    }
    
    /**
     * 如果文件存在,则从文件系统中加载
     */
    protected function requireFile($file) {
        if (file_exists($file)) {
            require $file;
            return true;
        }
        return false;
    }
}

// 使用自动加载器
$loader = new Autoloader();
$loader->addNamespace('App', __DIR__ . '/src');
$loader->addNamespace('Tests', __DIR__ . '/tests');
$loader->register();

echo "=== 自动加载演示 ===\n";
echo "自动加载器已注册\n";

// 现在可以直接使用类,无需手动require
// $user = new App\Models\User('张三', 'zhangsan@example.com');
// $controller = new App\Controllers\UserController();
?>

7.6.2 Composer自动加载

// composer.json
{
    "name": "myapp/php-tutorial",
    "description": "PHP教程示例项目",
    "type": "project",
    "autoload": {
        "psr-4": {
            "App\\": "src/",
            "Tests\\": "tests/"
        },
        "files": [
            "src/helpers.php"
        ],
        "classmap": [
            "legacy/"
        ]
    },
    "autoload-dev": {
        "psr-4": {
            "Tests\\": "tests/"
        }
    },
    "require": {
        "php": ">=7.4",
        "monolog/monolog": "^2.0"
    },
    "require-dev": {
        "phpunit/phpunit": "^9.0"
    }
}
<?php
// 使用Composer自动加载
require_once 'vendor/autoload.php';

use App\Models\User;
use App\Controllers\UserController;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;

// 创建日志记录器
$log = new Logger('app');
$log->pushHandler(new StreamHandler('app.log', Logger::WARNING));

// 使用应用类
$user = new User('张三', 'zhangsan@example.com');
$controller = new UserController();

$log->info('用户创建', ['user' => $user->getName()]);

echo "Composer自动加载演示完成\n";
?>

7.7 常用设计模式

7.7.1 单例模式

<?php
class Database {
    private static $instance = null;
    private $connection;
    private $host = 'localhost';
    private $username = 'root';
    private $password = '';
    private $database = 'test';
    
    // 私有构造函数,防止外部实例化
    private function __construct() {
        try {
            $this->connection = new PDO(
                "mysql:host={$this->host};dbname={$this->database}",
                $this->username,
                $this->password,
                [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
            );
        } catch (PDOException $e) {
            die("数据库连接失败:" . $e->getMessage());
        }
    }
    
    // 防止克隆
    private function __clone() {}
    
    // 防止反序列化
    public function __wakeup() {
        throw new Exception("不能反序列化单例");
    }
    
    // 获取实例
    public static function getInstance() {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    // 获取连接
    public function getConnection() {
        return $this->connection;
    }
    
    // 执行查询
    public function query($sql, $params = []) {
        try {
            $stmt = $this->connection->prepare($sql);
            $stmt->execute($params);
            return $stmt;
        } catch (PDOException $e) {
            throw new Exception("查询执行失败:" . $e->getMessage());
        }
    }
}

// 配置管理单例
class Config {
    private static $instance = null;
    private $config = [];
    
    private function __construct() {
        // 加载配置文件
        $this->config = [
            'app' => [
                'name' => 'PHP教程应用',
                'version' => '1.0.0',
                'debug' => true
            ],
            'database' => [
                'host' => 'localhost',
                'port' => 3306,
                'name' => 'tutorial_db'
            ],
            'cache' => [
                'driver' => 'redis',
                'ttl' => 3600
            ]
        ];
    }
    
    public static function getInstance() {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    public function get($key, $default = null) {
        $keys = explode('.', $key);
        $value = $this->config;
        
        foreach ($keys as $k) {
            if (isset($value[$k])) {
                $value = $value[$k];
            } else {
                return $default;
            }
        }
        
        return $value;
    }
    
    public function set($key, $value) {
        $keys = explode('.', $key);
        $config = &$this->config;
        
        foreach ($keys as $k) {
            if (!isset($config[$k])) {
                $config[$k] = [];
            }
            $config = &$config[$k];
        }
        
        $config = $value;
    }
}

// 使用单例模式
echo "=== 单例模式演示 ===\n";

// 配置管理
$config = Config::getInstance();
echo "应用名称:" . $config->get('app.name') . "\n";
echo "数据库主机:" . $config->get('database.host') . "\n";
echo "缓存TTL:" . $config->get('cache.ttl') . "\n";

// 验证单例
$config2 = Config::getInstance();
var_dump($config === $config2); // true

// 数据库连接(注释掉,因为可能没有实际数据库)
// $db1 = Database::getInstance();
// $db2 = Database::getInstance();
// var_dump($db1 === $db2); // true
?>

7.7.2 工厂模式

<?php
// 产品接口
interface LoggerInterface {
    public function log($message, $level = 'INFO');
    public function getType();
}

// 具体产品
class FileLogger implements LoggerInterface {
    private $filename;
    
    public function __construct($filename = 'app.log') {
        $this->filename = $filename;
    }
    
    public function log($message, $level = 'INFO') {
        $timestamp = date('Y-m-d H:i:s');
        $logEntry = "[$timestamp] [$level] $message" . PHP_EOL;
        file_put_contents($this->filename, $logEntry, FILE_APPEND | LOCK_EX);
    }
    
    public function getType() {
        return 'file';
    }
}

class DatabaseLogger implements LoggerInterface {
    private $table;
    
    public function __construct($table = 'logs') {
        $this->table = $table;
    }
    
    public function log($message, $level = 'INFO') {
        // 模拟数据库日志记录
        echo "数据库日志:插入到 {$this->table} 表 - [$level] $message\n";
    }
    
    public function getType() {
        return 'database';
    }
}

class EmailLogger implements LoggerInterface {
    private $email;
    
    public function __construct($email = 'admin@example.com') {
        $this->email = $email;
    }
    
    public function log($message, $level = 'INFO') {
        if ($level === 'ERROR' || $level === 'CRITICAL') {
            echo "邮件日志:发送到 {$this->email} - [$level] $message\n";
        }
    }
    
    public function getType() {
        return 'email';
    }
}

// 简单工厂
class LoggerFactory {
    public static function create($type, $config = []) {
        switch (strtolower($type)) {
            case 'file':
                $filename = $config['filename'] ?? 'app.log';
                return new FileLogger($filename);
                
            case 'database':
                $table = $config['table'] ?? 'logs';
                return new DatabaseLogger($table);
                
            case 'email':
                $email = $config['email'] ?? 'admin@example.com';
                return new EmailLogger($email);
                
            default:
                throw new InvalidArgumentException("不支持的日志类型:$type");
        }
    }
    
    public static function createMultiple($types) {
        $loggers = [];
        foreach ($types as $type => $config) {
            $loggers[] = self::create($type, $config);
        }
        return $loggers;
    }
}

// 抽象工厂模式
abstract class AbstractLoggerFactory {
    abstract public function createFileLogger();
    abstract public function createDatabaseLogger();
    abstract public function createEmailLogger();
}

class ProductionLoggerFactory extends AbstractLoggerFactory {
    public function createFileLogger() {
        return new FileLogger('/var/log/app/production.log');
    }
    
    public function createDatabaseLogger() {
        return new DatabaseLogger('production_logs');
    }
    
    public function createEmailLogger() {
        return new EmailLogger('admin@production.com');
    }
}

class DevelopmentLoggerFactory extends AbstractLoggerFactory {
    public function createFileLogger() {
        return new FileLogger('debug.log');
    }
    
    public function createDatabaseLogger() {
        return new DatabaseLogger('dev_logs');
    }
    
    public function createEmailLogger() {
        return new EmailLogger('dev@localhost.com');
    }
}

// 使用工厂模式
echo "=== 工厂模式演示 ===\n";

// 简单工厂
echo "--- 简单工厂 ---\n";
$fileLogger = LoggerFactory::create('file', ['filename' => 'test.log']);
$dbLogger = LoggerFactory::create('database', ['table' => 'app_logs']);
$emailLogger = LoggerFactory::create('email', ['email' => 'test@example.com']);

$fileLogger->log('这是一个文件日志消息');
$dbLogger->log('这是一个数据库日志消息', 'WARNING');
$emailLogger->log('这是一个严重错误', 'ERROR');

// 批量创建
echo "\n--- 批量创建 ---\n";
$loggers = LoggerFactory::createMultiple([
    'file' => ['filename' => 'batch.log'],
    'database' => ['table' => 'batch_logs'],
    'email' => ['email' => 'batch@example.com']
]);

foreach ($loggers as $logger) {
    $logger->log("批量日志消息 - 类型:" . $logger->getType());
}

// 抽象工厂
echo "\n--- 抽象工厂 ---\n";
$environment = 'development'; // 或 'production'

if ($environment === 'production') {
    $factory = new ProductionLoggerFactory();
} else {
    $factory = new DevelopmentLoggerFactory();
}

$fileLogger = $factory->createFileLogger();
$dbLogger = $factory->createDatabaseLogger();
$emailLogger = $factory->createEmailLogger();

$fileLogger->log("环境:$environment - 文件日志");
$dbLogger->log("环境:$environment - 数据库日志");
$emailLogger->log("环境:$environment - 严重错误", 'CRITICAL');
?>

7.7.3 观察者模式

<?php
// 观察者接口
interface ObserverInterface {
    public function update($subject, $event, $data = null);
}

// 主题接口
interface SubjectInterface {
    public function attach(ObserverInterface $observer);
    public function detach(ObserverInterface $observer);
    public function notify($event, $data = null);
}

// 具体主题 - 用户模型
class User implements SubjectInterface {
    private $observers = [];
    private $name;
    private $email;
    private $status;
    
    public function __construct($name, $email) {
        $this->name = $name;
        $this->email = $email;
        $this->status = 'active';
    }
    
    public function attach(ObserverInterface $observer) {
        $this->observers[] = $observer;
    }
    
    public function detach(ObserverInterface $observer) {
        $key = array_search($observer, $this->observers, true);
        if ($key !== false) {
            unset($this->observers[$key]);
        }
    }
    
    public function notify($event, $data = null) {
        foreach ($this->observers as $observer) {
            $observer->update($this, $event, $data);
        }
    }
    
    public function setName($name) {
        $oldName = $this->name;
        $this->name = $name;
        $this->notify('name_changed', ['old' => $oldName, 'new' => $name]);
    }
    
    public function setEmail($email) {
        $oldEmail = $this->email;
        $this->email = $email;
        $this->notify('email_changed', ['old' => $oldEmail, 'new' => $email]);
    }
    
    public function setStatus($status) {
        $oldStatus = $this->status;
        $this->status = $status;
        $this->notify('status_changed', ['old' => $oldStatus, 'new' => $status]);
    }
    
    public function getName() {
        return $this->name;
    }
    
    public function getEmail() {
        return $this->email;
    }
    
    public function getStatus() {
        return $this->status;
    }
}

// 具体观察者 - 邮件通知
class EmailNotificationObserver implements ObserverInterface {
    public function update($subject, $event, $data = null) {
        switch ($event) {
            case 'email_changed':
                $this->sendEmailChangeNotification($subject, $data);
                break;
            case 'status_changed':
                if ($data['new'] === 'suspended') {
                    $this->sendSuspensionNotification($subject);
                }
                break;
        }
    }
    
    private function sendEmailChangeNotification($user, $data) {
        echo "邮件通知:用户 {$user->getName()} 的邮箱从 {$data['old']} 更改为 {$data['new']}\n";
    }
    
    private function sendSuspensionNotification($user) {
        echo "邮件通知:用户 {$user->getName()} 账户已被暂停\n";
    }
}

// 具体观察者 - 日志记录
class LoggingObserver implements ObserverInterface {
    public function update($subject, $event, $data = null) {
        $timestamp = date('Y-m-d H:i:s');
        $userName = $subject->getName();
        
        switch ($event) {
            case 'name_changed':
                echo "日志:[$timestamp] 用户名更改 - $userName: {$data['old']} -> {$data['new']}\n";
                break;
            case 'email_changed':
                echo "日志:[$timestamp] 邮箱更改 - $userName: {$data['old']} -> {$data['new']}\n";
                break;
            case 'status_changed':
                echo "日志:[$timestamp] 状态更改 - $userName: {$data['old']} -> {$data['new']}\n";
                break;
        }
    }
}

// 具体观察者 - 缓存更新
class CacheObserver implements ObserverInterface {
    private $cache = [];
    
    public function update($subject, $event, $data = null) {
        $userId = spl_object_hash($subject);
        
        switch ($event) {
            case 'name_changed':
            case 'email_changed':
            case 'status_changed':
                $this->invalidateUserCache($userId);
                $this->updateUserCache($subject);
                break;
        }
    }
    
    private function invalidateUserCache($userId) {
        unset($this->cache[$userId]);
        echo "缓存:清除用户 $userId 的缓存\n";
    }
    
    private function updateUserCache($user) {
        $userId = spl_object_hash($user);
        $this->cache[$userId] = [
            'name' => $user->getName(),
            'email' => $user->getEmail(),
            'status' => $user->getStatus(),
            'cached_at' => time()
        ];
        echo "缓存:更新用户 {$user->getName()} 的缓存\n";
    }
    
    public function getCache() {
        return $this->cache;
    }
}

// 使用观察者模式
echo "=== 观察者模式演示 ===\n";

// 创建用户
$user = new User('张三', 'zhangsan@example.com');

// 创建观察者
$emailObserver = new EmailNotificationObserver();
$loggingObserver = new LoggingObserver();
$cacheObserver = new CacheObserver();

// 注册观察者
$user->attach($emailObserver);
$user->attach($loggingObserver);
$user->attach($cacheObserver);

echo "初始用户信息:{$user->getName()}, {$user->getEmail()}, {$user->getStatus()}\n\n";

// 触发事件
echo "--- 更改用户名 ---\n";
$user->setName('张三丰');

echo "\n--- 更改邮箱 ---\n";
$user->setEmail('zhangsanfeng@example.com');

echo "\n--- 暂停用户 ---\n";
$user->setStatus('suspended');

echo "\n--- 移除邮件观察者后再次更改状态 ---\n";
$user->detach($emailObserver);
$user->setStatus('active');

echo "\n--- 缓存内容 ---\n";
print_r($cacheObserver->getCache());
?>

7.8 本章小结

面向对象编程是PHP的重要特性,本章详细介绍了:

核心概念

  • 类和对象:封装数据和行为的基本单位
  • 属性和方法:类的数据成员和行为定义
  • 访问修饰符:控制成员的可见性(public、protected、private)
  • 魔术方法:PHP提供的特殊方法,如构造函数、析构函数等

面向对象特性

  • 继承:代码复用和扩展的重要机制
  • 多态:同一接口的不同实现
  • 抽象类:定义通用接口和部分实现
  • 接口:定义类必须实现的契约
  • Trait:代码复用的水平组合机制

高级特性

  • 命名空间:避免命名冲突,组织代码结构
  • 自动加载:自动加载类文件,提高开发效率
  • 设计模式:解决常见问题的最佳实践

最佳实践

  1. 遵循SOLID原则
  2. 使用合适的设计模式
  3. 合理组织命名空间
  4. 编写可测试的代码
  5. 注重代码的可读性和可维护性

7.9 实践练习

练习1:图书管理系统

设计一个图书管理系统,包含以下要求: - 创建Book、Author、Library类 - 实现借书、还书功能 - 使用接口定义可借阅物品 - 使用观察者模式通知图书状态变化

练习2:电商购物车

实现一个购物车系统: - 使用工厂模式创建不同类型的商品 - 实现购物车的添加、删除、计算总价功能 - 使用策略模式实现不同的优惠计算 - 使用单例模式管理购物车会话

练习3:日志系统

设计一个灵活的日志系统: - 支持多种日志输出方式(文件、数据库、邮件) - 使用抽象工厂模式创建不同环境的日志器 - 实现日志级别过滤 - 使用装饰器模式添加日志格式化功能

7.10 扩展阅读


下一章预告:第八章将介绍错误处理与异常,包括错误类型、异常处理机制、自定义异常、调试技巧等内容。