00-PHP进阶知识

6 阅读17分钟

PHP 进阶知识与设计模式

这部分内容帮助你更好地理解 Hyperf 的设计理念和实现方式

1. 设计模式

1.1 单例模式(Singleton)

目的:确保一个类只有一个实例。

<?php
class Database
{
    private static $instance = null;
    private $connection;
    
    // 私有构造函数:防止外部 new
    private function __construct()
    {
        $this->connection = new PDO('mysql:host=localhost;dbname=test', 'root', 'root');
    }
    
    // 私有克隆方法:防止克隆
    private function __clone() {}
    
    // 获取实例
    public static function getInstance()
    {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        
        return self::$instance;
    }
    
    public function query($sql)
    {
        return $this->connection->query($sql);
    }
}

// 使用
$db1 = Database::getInstance();
$db2 = Database::getInstance();

var_dump($db1 === $db2);  // true(同一个实例)

// ❌ 错误:不能 new
$db3 = new Database();  // 错误:构造函数是私有的

在 Hyperf 中的应用

<?php
// Hyperf 的 DI 容器默认使用单例模式
use Hyperf\Di\Annotation\Inject;

class UserController
{
    #[Inject]
    private UserService $userService;  // 单例,整个应用共享
}

1.2 工厂模式(Factory)

目的:创建对象时不暴露创建逻辑。

<?php
// 简单工厂
class PaymentFactory
{
    public static function create(string $type): PaymentInterface
    {
        switch ($type) {
            case 'alipay':
                return new AlipayPayment();
            case 'wechat':
                return new WechatPayment();
            case 'credit_card':
                return new CreditCardPayment();
            default:
                throw new \Exception("不支持的支付方式:{$type}");
        }
    }
}

// 使用
$payment = PaymentFactory::create('alipay');
$payment->pay(100);

// 优势:
// 1. 创建逻辑集中管理
// 2. 新增支付方式只需修改工厂类
// 3. 使用者不需要知道具体实现类

在 Hyperf 中的应用

<?php
use Hyperf\AsyncQueue\Driver\DriverFactory;

// DriverFactory 根据配置创建不同的驱动
$driver = $driverFactory->get('default');

1.3 策略模式(Strategy)

目的:定义一系列算法,让它们可以互相替换。

<?php
// 策略接口
interface DiscountStrategy
{
    public function calculate(float $price): float;
}

// 具体策略:普通用户
class NormalDiscount implements DiscountStrategy
{
    public function calculate(float $price): float
    {
        return $price;  // 无折扣
    }
}

// 具体策略:VIP 用户
class VipDiscount implements DiscountStrategy
{
    public function calculate(float $price): float
    {
        return $price * 0.9;  // 9 折
    }
}

// 具体策略:SVIP 用户
class SvipDiscount implements DiscountStrategy
{
    public function calculate(float $price): float
    {
        return $price * 0.8;  // 8 折
    }
}

// 上下文:订单
class Order
{
    private $price;
    private $discountStrategy;
    
    public function __construct(float $price, DiscountStrategy $strategy)
    {
        $this->price = $price;
        $this->discountStrategy = $strategy;
    }
    
    public function getFinalPrice(): float
    {
        return $this->discountStrategy->calculate($this->price);
    }
}

// 使用
$normalOrder = new Order(100, new NormalDiscount());
echo $normalOrder->getFinalPrice();  // 100

$vipOrder = new Order(100, new VipDiscount());
echo $vipOrder->getFinalPrice();  // 90

$svipOrder = new Order(100, new SvipDiscount());
echo $svipOrder->getFinalPrice();  // 80

1.4 观察者模式(Observer)

目的:定义对象间的一对多依赖关系,当一个对象状态改变时,所有依赖它的对象都会收到通知。

<?php
// 观察者接口
interface Observer
{
    public function update(Subject $subject): void;
}

// 主题(被观察者)
class Subject
{
    private $observers = [];
    private $state;
    
    // 添加观察者
    public function attach(Observer $observer)
    {
        $this->observers[] = $observer;
    }
    
    // 设置状态
    public function setState($state)
    {
        $this->state = $state;
        $this->notify();  // 通知所有观察者
    }
    
    public function getState()
    {
        return $this->state;
    }
    
    // 通知所有观察者
    private function notify()
    {
        foreach ($this->observers as $observer) {
            $observer->update($this);
        }
    }
}

// 具体观察者:邮件通知
class EmailObserver implements Observer
{
    public function update(Subject $subject): void
    {
        echo "发送邮件:状态变更为 {$subject->getState()}\n";
    }
}

// 具体观察者:短信通知
class SmsObserver implements Observer
{
    public function update(Subject $subject): void
    {
        echo "发送短信:状态变更为 {$subject->getState()}\n";
    }
}

// 使用
$subject = new Subject();

// 注册观察者
$subject->attach(new EmailObserver());
$subject->attach(new SmsObserver());

// 改变状态,自动通知观察者
$subject->setState('订单已支付');
// 输出:
// 发送邮件:状态变更为 订单已支付
// 发送短信:状态变更为 订单已支付

在 Hyperf 中的应用

<?php
// Hyperf 的事件系统就是观察者模式
use App\Event\UserRegistered;
use Hyperf\Event\Annotation\Listener;

#[Listener]
class SendWelcomeEmailListener
{
    public function process(UserRegistered $event)
    {
        // 当用户注册事件触发时,自动发送欢迎邮件
    }
}

1.5 依赖注入容器(IoC)

目的:自动管理对象的创建和依赖注入。

<?php
// 简单的 DI 容器实现
class Container
{
    private $bindings = [];
    private $instances = [];
    
    // 绑定接口到实现
    public function bind(string $abstract, $concrete)
    {
        $this->bindings[$abstract] = $concrete;
    }
    
    // 绑定单例
    public function singleton(string $abstract, $concrete)
    {
        $this->bind($abstract, $concrete);
    }
    
    // 解析(创建对象)
    public function make(string $abstract)
    {
        // 如果是单例且已创建,直接返回
        if (isset($this->instances[$abstract])) {
            return $this->instances[$abstract];
        }
        
        // 获取具体类
        $concrete = $this->bindings[$abstract] ?? $abstract;
        
        // 如果是闭包,直接执行
        if ($concrete instanceof Closure) {
            return $concrete($this);
        }
        
        // 反射创建对象
        $reflector = new ReflectionClass($concrete);
        
        // 获取构造函数
        $constructor = $reflector->getConstructor();
        
        // 如果没有构造函数,直接创建
        if ($constructor === null) {
            return new $concrete;
        }
        
        // 获取构造函数参数
        $parameters = $constructor->getParameters();
        
        // 解析参数依赖
        $dependencies = [];
        foreach ($parameters as $parameter) {
            $type = $parameter->getType();
            
            if ($type && !$type->isBuiltin()) {
                // 递归解析依赖
                $dependencies[] = $this->make($type->getName());
            }
        }
        
        // 创建对象
        $instance = $reflector->newInstanceArgs($dependencies);
        
        // 保存单例
        $this->instances[$abstract] = $instance;
        
        return $instance;
    }
}

// 使用
$container = new Container();

// 绑定接口到实现
$container->bind(CacheInterface::class, RedisCache::class);

// 自动创建对象并注入依赖
$userService = $container->make(UserService::class);
// UserService 依赖 CacheInterface,容器会自动创建 RedisCache 并注入

1.6 装饰器模式(Decorator)

目的:动态地给对象添加新功能,不改变其结构。

<?php
// 组件接口
interface CoffeeInterface
{
    public function getCost(): float;
    public function getDescription(): string;
}

// 基础组件:咖啡
class SimpleCoffee implements CoffeeInterface
{
    public function getCost(): float
    {
        return 10;
    }
    
    public function getDescription(): string
    {
        return '简单咖啡';
    }
}

// 装饰器抽象类
abstract class CoffeeDecorator implements CoffeeInterface
{
    protected $coffee;
    
    public function __construct(CoffeeInterface $coffee)
    {
        $this->coffee = $coffee;
    }
}

// 具体装饰器:牛奶
class MilkDecorator extends CoffeeDecorator
{
    public function getCost(): float
    {
        return $this->coffee->getCost() + 2;
    }
    
    public function getDescription(): string
    {
        return $this->coffee->getDescription() . ' + 牛奶';
    }
}

// 具体装饰器:糖
class SugarDecorator extends CoffeeDecorator
{
    public function getCost(): float
    {
        return $this->coffee->getCost() + 1;
    }
    
    public function getDescription(): string
    {
        return $this->coffee->getDescription() . ' + 糖';
    }
}

// 具体装饰器:香草
class VanillaDecorator extends CoffeeDecorator
{
    public function getCost(): float
    {
        return $this->coffee->getCost() + 3;
    }
    
    public function getDescription(): string
    {
        return $this->coffee->getDescription() . ' + 香草';
    }
}

// 使用:可以动态组合
$coffee = new SimpleCoffee();
echo $coffee->getDescription() . ': ' . $coffee->getCost();  // 简单咖啡: 10

$coffee = new MilkDecorator($coffee);
echo $coffee->getDescription() . ': ' . $coffee->getCost();  // 简单咖啡 + 牛奶: 12

$coffee = new SugarDecorator($coffee);
echo $coffee->getDescription() . ': ' . $coffee->getCost();  // 简单咖啡 + 牛奶 + 糖: 13

$coffee = new VanillaDecorator($coffee);
echo $coffee->getDescription() . ': ' . $coffee->getCost();  // 简单咖啡 + 牛奶 + 糖 + 香草: 16

在 Hyperf 中的应用

<?php
// Hyperf 的中间件就是装饰器模式
use Hyperf\HttpServer\Contract\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

class LogMiddleware implements MiddlewareInterface
{
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        // 前置处理
        echo "请求开始\n";
        
        // 调用下一个中间件
        $response = $handler->handle($request);
        
        // 后置处理
        echo "请求结束\n";
        
        return $response;
    }
}

1.7 适配器模式(Adapter)

目的:将一个类的接口转换成客户希望的另一个接口。

<?php
// 目标接口
interface PaymentInterface
{
    public function pay(float $amount): bool;
}

// 旧的支付类(不兼容 PaymentInterface)
class OldPaymentSystem
{
    public function makePayment($money)
    {
        echo "使用旧系统支付: {$money}\n";
        return true;
    }
}

// 适配器:让旧系统适配新接口
class PaymentAdapter implements PaymentInterface
{
    private $oldSystem;
    
    public function __construct(OldPaymentSystem $oldSystem)
    {
        $this->oldSystem = $oldSystem;
    }
    
    public function pay(float $amount): bool
    {
        // 转换调用
        return $this->oldSystem->makePayment($amount);
    }
}

// 使用
$oldSystem = new OldPaymentSystem();
$payment = new PaymentAdapter($oldSystem);

// 现在可以使用统一接口
$payment->pay(100);  // 使用旧系统支付: 100

实际应用

<?php
// 不同缓存系统的适配器
interface CacheInterface
{
    public function get(string $key);
    public function set(string $key, $value, int $ttl);
}

// Redis 适配器
class RedisAdapter implements CacheInterface
{
    private $redis;
    
    public function __construct($redis)
    {
        $this->redis = $redis;
    }
    
    public function get(string $key)
    {
        return $this->redis->get($key);
    }
    
    public function set(string $key, $value, int $ttl)
    {
        return $this->redis->setex($key, $ttl, $value);
    }
}

// Memcached 适配器
class MemcachedAdapter implements CacheInterface
{
    private $memcached;
    
    public function __construct($memcached)
    {
        $this->memcached = $memcached;
    }
    
    public function get(string $key)
    {
        return $this->memcached->get($key);
    }
    
    public function set(string $key, $value, int $ttl)
    {
        return $this->memcached->set($key, $value, $ttl);
    }
}

// 使用:统一接口,可以随时切换实现
$cache = new RedisAdapter($redis);
// $cache = new MemcachedAdapter($memcached);

$cache->set('user:1', ['name' => 'John'], 3600);
$user = $cache->get('user:1');

1.8 代理模式(Proxy)

目的:为其他对象提供一个代理以控制对这个对象的访问。

<?php
// 主体接口
interface ImageInterface
{
    public function display(): void;
}

// 真实主体:图片
class RealImage implements ImageInterface
{
    private $filename;
    
    public function __construct(string $filename)
    {
        $this->filename = $filename;
        $this->loadFromDisk();
    }
    
    private function loadFromDisk()
    {
        echo "从磁盘加载图片: {$this->filename}\n";
        sleep(2);  // 模拟耗时操作
    }
    
    public function display(): void
    {
        echo "显示图片: {$this->filename}\n";
    }
}

// 代理:延迟加载图片
class ImageProxy implements ImageInterface
{
    private $filename;
    private $realImage;
    
    public function __construct(string $filename)
    {
        $this->filename = $filename;
    }
    
    public function display(): void
    {
        // 延迟加载:只有在调用 display 时才创建真实对象
        if ($this->realImage === null) {
            $this->realImage = new RealImage($this->filename);
        }
        
        $this->realImage->display();
    }
}

// 使用
$image1 = new ImageProxy('photo1.jpg');  // 没有加载
$image2 = new ImageProxy('photo2.jpg');  // 没有加载

// 只有在显示时才加载
$image1->display();  // 从磁盘加载图片: photo1.jpg  显示图片: photo1.jpg
$image1->display();  // 显示图片: photo1.jpg(不再加载)

在 Hyperf 中的应用

<?php
// Hyperf AOP 使用代理模式
use Hyperf\Di\Annotation\Aspect;
use Hyperf\Di\Aop\AbstractAspect;
use Hyperf\Di\Aop\ProceedingJoinPoint;

#[Aspect]
class CacheAspect extends AbstractAspect
{
    public $classes = [
        UserService::class . '::getUser'
    ];
    
    public function process(ProceedingJoinPoint $proceedingJoinPoint)
    {
        $key = 'user:' . $proceedingJoinPoint->arguments['keys']['id'];
        
        // 从缓存获取
        $cache = $this->redis->get($key);
        if ($cache) {
            return json_decode($cache, true);
        }
        
        // 执行原方法
        $result = $proceedingJoinPoint->process();
        
        // 缓存结果
        $this->redis->setex($key, 3600, json_encode($result));
        
        return $result;
    }
}

1.9 责任链模式(Chain of Responsibility)

目的:将请求的发送者和接收者解耦,让多个对象都有机会处理请求。

<?php
// 抽象处理器
abstract class Handler
{
    protected $nextHandler;
    
    public function setNext(Handler $handler): Handler
    {
        $this->nextHandler = $handler;
        return $handler;
    }
    
    abstract public function handle($request);
}

// 具体处理器:权限检查
class AuthHandler extends Handler
{
    public function handle($request)
    {
        if (!isset($request['token'])) {
            return '认证失败';
        }
        
        echo "权限检查通过\n";
        
        // 传递给下一个处理器
        if ($this->nextHandler) {
            return $this->nextHandler->handle($request);
        }
        
        return '处理完成';
    }
}

// 具体处理器:参数验证
class ValidationHandler extends Handler
{
    public function handle($request)
    {
        if (!isset($request['data'])) {
            return '参数验证失败';
        }
        
        echo "参数验证通过\n";
        
        if ($this->nextHandler) {
            return $this->nextHandler->handle($request);
        }
        
        return '处理完成';
    }
}

// 具体处理器:业务处理
class BusinessHandler extends Handler
{
    public function handle($request)
    {
        echo "执行业务逻辑\n";
        
        if ($this->nextHandler) {
            return $this->nextHandler->handle($request);
        }
        
        return '处理完成';
    }
}

// 使用:构建责任链
$auth = new AuthHandler();
$validation = new ValidationHandler();
$business = new BusinessHandler();

$auth->setNext($validation)->setNext($business);

// 请求通过责任链
$request = ['token' => 'abc123', 'data' => ['name' => 'John']];
echo $auth->handle($request);

// 输出:
// 权限检查通过
// 参数验证通过
// 执行业务逻辑
// 处理完成

在 Hyperf 中的应用

<?php
// Hyperf 的中间件管道就是责任链模式
class MiddlewarePipeline
{
    private $middlewares = [];
    
    public function pipe($middleware)
    {
        $this->middlewares[] = $middleware;
        return $this;
    }
    
    public function handle($request)
    {
        $next = function ($request) {
            return $request;
        };
        
        // 构建责任链
        foreach (array_reverse($this->middlewares) as $middleware) {
            $next = function ($request) use ($middleware, $next) {
                return $middleware->process($request, $next);
            };
        }
        
        return $next($request);
    }
}

1.10 命令模式(Command)

目的:将请求封装成对象,从而使你可以用不同的请求对客户进行参数化。

<?php
// 命令接口
interface CommandInterface
{
    public function execute(): void;
    public function undo(): void;
}

// 接收者:灯
class Light
{
    public function turnOn()
    {
        echo "灯已打开\n";
    }
    
    public function turnOff()
    {
        echo "灯已关闭\n";
    }
}

// 具体命令:打开灯
class TurnOnCommand implements CommandInterface
{
    private $light;
    
    public function __construct(Light $light)
    {
        $this->light = $light;
    }
    
    public function execute(): void
    {
        $this->light->turnOn();
    }
    
    public function undo(): void
    {
        $this->light->turnOff();
    }
}

// 具体命令:关闭灯
class TurnOffCommand implements CommandInterface
{
    private $light;
    
    public function __construct(Light $light)
    {
        $this->light = $light;
    }
    
    public function execute(): void
    {
        $this->light->turnOff();
    }
    
    public function undo(): void
    {
        $this->light->turnOn();
    }
}

// 调用者:遥控器
class RemoteControl
{
    private $command;
    private $history = [];
    
    public function setCommand(CommandInterface $command)
    {
        $this->command = $command;
    }
    
    public function pressButton()
    {
        $this->command->execute();
        $this->history[] = $this->command;
    }
    
    public function pressUndo()
    {
        if (!empty($this->history)) {
            $command = array_pop($this->history);
            $command->undo();
        }
    }
}

// 使用
$light = new Light();
$turnOn = new TurnOnCommand($light);
$turnOff = new TurnOffCommand($light);

$remote = new RemoteControl();

$remote->setCommand($turnOn);
$remote->pressButton();  // 灯已打开

$remote->setCommand($turnOff);
$remote->pressButton();  // 灯已关闭

$remote->pressUndo();  // 灯已打开(撤销)

实际应用:队列任务

<?php
// 队列任务就是命令模式
use Hyperf\AsyncQueue\Annotation\AsyncQueueMessage;

#[AsyncQueueMessage]
class SendEmailCommand
{
    public $to;
    public $subject;
    public $body;
    
    public function __construct($to, $subject, $body)
    {
        $this->to = $to;
        $this->subject = $subject;
        $this->body = $body;
    }
}

// 投递任务
$command = new SendEmailCommand('user@example.com', '标题', '内容');
$this->driver->push($command);

// 消费者执行命令
class SendEmailConsumer
{
    public function consume(SendEmailCommand $command)
    {
        // 执行命令
        mail($command->to, $command->subject, $command->body);
    }
}

1.11 状态模式(State)

目的:允许对象在内部状态改变时改变它的行为。

<?php
// 状态接口
interface OrderStateInterface
{
    public function pay(Order $order): void;
    public function ship(Order $order): void;
    public function complete(Order $order): void;
    public function cancel(Order $order): void;
}

// 上下文:订单
class Order
{
    private $state;
    
    public function __construct()
    {
        // 初始状态:待支付
        $this->state = new PendingState();
    }
    
    public function setState(OrderStateInterface $state)
    {
        $this->state = $state;
    }
    
    public function pay()
    {
        $this->state->pay($this);
    }
    
    public function ship()
    {
        $this->state->ship($this);
    }
    
    public function complete()
    {
        $this->state->complete($this);
    }
    
    public function cancel()
    {
        $this->state->cancel($this);
    }
}

// 具体状态:待支付
class PendingState implements OrderStateInterface
{
    public function pay(Order $order): void
    {
        echo "订单已支付\n";
        $order->setState(new PaidState());
    }
    
    public function ship(Order $order): void
    {
        echo "订单未支付,无法发货\n";
    }
    
    public function complete(Order $order): void
    {
        echo "订单未支付,无法完成\n";
    }
    
    public function cancel(Order $order): void
    {
        echo "订单已取消\n";
        $order->setState(new CancelledState());
    }
}

// 具体状态:已支付
class PaidState implements OrderStateInterface
{
    public function pay(Order $order): void
    {
        echo "订单已支付,无需重复支付\n";
    }
    
    public function ship(Order $order): void
    {
        echo "订单已发货\n";
        $order->setState(new ShippedState());
    }
    
    public function complete(Order $order): void
    {
        echo "订单未发货,无法完成\n";
    }
    
    public function cancel(Order $order): void
    {
        echo "订单已支付,无法取消\n";
    }
}

// 具体状态:已发货
class ShippedState implements OrderStateInterface
{
    public function pay(Order $order): void
    {
        echo "订单已支付\n";
    }
    
    public function ship(Order $order): void
    {
        echo "订单已发货\n";
    }
    
    public function complete(Order $order): void
    {
        echo "订单已完成\n";
        $order->setState(new CompletedState());
    }
    
    public function cancel(Order $order): void
    {
        echo "订单已发货,无法取消\n";
    }
}

// 具体状态:已完成
class CompletedState implements OrderStateInterface
{
    public function pay(Order $order): void { echo "订单已完成\n"; }
    public function ship(Order $order): void { echo "订单已完成\n"; }
    public function complete(Order $order): void { echo "订单已完成\n"; }
    public function cancel(Order $order): void { echo "订单已完成,无法取消\n"; }
}

// 具体状态:已取消
class CancelledState implements OrderStateInterface
{
    public function pay(Order $order): void { echo "订单已取消\n"; }
    public function ship(Order $order): void { echo "订单已取消\n"; }
    public function complete(Order $order): void { echo "订单已取消\n"; }
    public function cancel(Order $order): void { echo "订单已取消\n"; }
}

// 使用
$order = new Order();

$order->ship();      // 订单未支付,无法发货
$order->pay();       // 订单已支付
$order->ship();      // 订单已发货
$order->cancel();    // 订单已发货,无法取消
$order->complete();  // 订单已完成

1.12 建造者模式(Builder)

目的:分步骤构建复杂对象,使构建过程和表示分离。

<?php
// 产品:SQL查询
class SqlQuery
{
    public $table;
    public $where = [];
    public $orderBy = [];
    public $limit;
    public $offset;
    
    public function toSql(): string
    {
        $sql = "SELECT * FROM {$this->table}";
        
        if (!empty($this->where)) {
            $sql .= " WHERE " . implode(' AND ', $this->where);
        }
        
        if (!empty($this->orderBy)) {
            $sql .= " ORDER BY " . implode(', ', $this->orderBy);
        }
        
        if ($this->limit) {
            $sql .= " LIMIT {$this->limit}";
        }
        
        if ($this->offset) {
            $sql .= " OFFSET {$this->offset}";
        }
        
        return $sql;
    }
}

// 建造者
class QueryBuilder
{
    private $query;
    
    public function __construct()
    {
        $this->query = new SqlQuery();
    }
    
    public function table(string $table): self
    {
        $this->query->table = $table;
        return $this;
    }
    
    public function where(string $field, string $operator, $value): self
    {
        $this->query->where[] = "{$field} {$operator} '{$value}'";
        return $this;
    }
    
    public function orderBy(string $field, string $direction = 'ASC'): self
    {
        $this->query->orderBy[] = "{$field} {$direction}";
        return $this;
    }
    
    public function limit(int $limit): self
    {
        $this->query->limit = $limit;
        return $this;
    }
    
    public function offset(int $offset): self
    {
        $this->query->offset = $offset;
        return $this;
    }
    
    public function build(): SqlQuery
    {
        return $this->query;
    }
}

// 使用:链式调用构建复杂查询
$builder = new QueryBuilder();
$query = $builder
    ->table('users')
    ->where('age', '>', 18)
    ->where('status', '=', 'active')
    ->orderBy('created_at', 'DESC')
    ->limit(10)
    ->offset(20)
    ->build();

echo $query->toSql();
// SELECT * FROM users WHERE age > '18' AND status = 'active' 
// ORDER BY created_at DESC LIMIT 10 OFFSET 20

Hyperf 中的应用

<?php
// Hyperf 的查询构建器就是建造者模式
use Hyperf\DbConnection\Db;

$users = Db::table('users')
    ->where('age', '>', 18)
    ->where('status', 'active')
    ->orderBy('created_at', 'desc')
    ->limit(10)
    ->get();

1.13 模板方法模式(Template Method)

目的:定义算法的骨架,将某些步骤延迟到子类实现。

<?php
// 抽象类:定义算法骨架
abstract class DataExporter
{
    // 模板方法:定义导出流程
    final public function export(array $data): string
    {
        // 1. 获取数据
        $fetchedData = $this->fetchData($data);
        
        // 2. 转换数据
        $transformedData = $this->transform($fetchedData);
        
        // 3. 格式化数据(子类实现)
        $formatted = $this->format($transformedData);
        
        // 4. 保存文件
        $this->save($formatted);
        
        return $formatted;
    }
    
    // 钩子方法:子类可以选择重写
    protected function fetchData(array $data): array
    {
        return $data;
    }
    
    protected function transform(array $data): array
    {
        return $data;
    }
    
    // 抽象方法:子类必须实现
    abstract protected function format(array $data): string;
    
    protected function save(string $content): void
    {
        file_put_contents($this->getFilename(), $content);
    }
    
    abstract protected function getFilename(): string;
}

// 具体类:CSV导出
class CsvExporter extends DataExporter
{
    protected function format(array $data): string
    {
        $csv = [];
        
        // 表头
        if (!empty($data)) {
            $csv[] = implode(',', array_keys($data[0]));
        }
        
        // 数据行
        foreach ($data as $row) {
            $csv[] = implode(',', $row);
        }
        
        return implode("\n", $csv);
    }
    
    protected function getFilename(): string
    {
        return 'export.csv';
    }
}

// 具体类:JSON导出
class JsonExporter extends DataExporter
{
    protected function format(array $data): string
    {
        return json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
    }
    
    protected function getFilename(): string
    {
        return 'export.json';
    }
}

// 具体类:XML导出
class XmlExporter extends DataExporter
{
    protected function format(array $data): string
    {
        $xml = new \SimpleXMLElement('<root/>');
        
        foreach ($data as $row) {
            $item = $xml->addChild('item');
            foreach ($row as $key => $value) {
                $item->addChild($key, htmlspecialchars($value));
            }
        }
        
        return $xml->asXML();
    }
    
    protected function getFilename(): string
    {
        return 'export.xml';
    }
}

// 使用
$data = [
    ['id' => 1, 'name' => 'John', 'email' => 'john@test.com'],
    ['id' => 2, 'name' => 'Jane', 'email' => 'jane@test.com'],
];

$csvExporter = new CsvExporter();
$csvExporter->export($data);  // 生成 CSV

$jsonExporter = new JsonExporter();
$jsonExporter->export($data);  // 生成 JSON

$xmlExporter = new XmlExporter();
$xmlExporter->export($data);  // 生成 XML

1.14 迭代器模式(Iterator)

目的:提供一种方法顺序访问聚合对象中的元素,而不暴露其内部表示。

<?php
// 实现 Iterator 接口
class BookCollection implements \Iterator
{
    private $books = [];
    private $position = 0;
    
    public function addBook(Book $book)
    {
        $this->books[] = $book;
    }
    
    // Iterator 接口方法
    public function current(): mixed
    {
        return $this->books[$this->position];
    }
    
    public function next(): void
    {
        $this->position++;
    }
    
    public function key(): mixed
    {
        return $this->position;
    }
    
    public function valid(): bool
    {
        return isset($this->books[$this->position]);
    }
    
    public function rewind(): void
    {
        $this->position = 0;
    }
}

class Book
{
    public function __construct(
        public string $title,
        public string $author
    ) {}
}

// 使用
$collection = new BookCollection();
$collection->addBook(new Book('PHP高级编程', '张三'));
$collection->addBook(new Book('设计模式', '李四'));
$collection->addBook(new Book('算法导论', '王五'));

// 可以使用 foreach 遍历
foreach ($collection as $key => $book) {
    echo "{$key}: {$book->title} - {$book->author}\n";
}

生成器实现迭代器

<?php
// 使用生成器更简单
class BookCollection implements \IteratorAggregate
{
    private $books = [];
    
    public function addBook(Book $book)
    {
        $this->books[] = $book;
    }
    
    public function getIterator(): \Generator
    {
        foreach ($this->books as $book) {
            yield $book;
        }
    }
}

// 使用方式相同
foreach ($collection as $book) {
    echo "{$book->title}\n";
}

1.15 门面模式(Facade)

目的:为复杂子系统提供一个简单的接口。

<?php
// 复杂子系统
class FileSystem
{
    public function readFile(string $path): string
    {
        return file_get_contents($path);
    }
    
    public function writeFile(string $path, string $content): bool
    {
        return file_put_contents($path, $content) !== false;
    }
}

class Compressor
{
    public function compress(string $content): string
    {
        return gzencode($content);
    }
    
    public function decompress(string $content): string
    {
        return gzdecode($content);
    }
}

class Encryptor
{
    public function encrypt(string $content, string $key): string
    {
        return openssl_encrypt($content, 'AES-256-CBC', $key, 0, '1234567890123456');
    }
    
    public function decrypt(string $content, string $key): string
    {
        return openssl_decrypt($content, 'AES-256-CBC', $key, 0, '1234567890123456');
    }
}

// 门面:简化接口
class SecureFileFacade
{
    private $fileSystem;
    private $compressor;
    private $encryptor;
    private $key;
    
    public function __construct(string $key)
    {
        $this->fileSystem = new FileSystem();
        $this->compressor = new Compressor();
        $this->encryptor = new Encryptor();
        $this->key = $key;
    }
    
    // 简化的保存方法(压缩+加密+保存)
    public function save(string $path, string $content): bool
    {
        $compressed = $this->compressor->compress($content);
        $encrypted = $this->encryptor->encrypt($compressed, $this->key);
        return $this->fileSystem->writeFile($path, $encrypted);
    }
    
    // 简化的读取方法(读取+解密+解压)
    public function read(string $path): string
    {
        $encrypted = $this->fileSystem->readFile($path);
        $compressed = $this->encryptor->decrypt($encrypted, $this->key);
        return $this->compressor->decompress($compressed);
    }
}

// 使用:简单接口隐藏复杂操作
$facade = new SecureFileFacade('my-secret-key');

// 保存(自动压缩+加密)
$facade->save('data.enc', 'This is sensitive data');

// 读取(自动解密+解压)
$content = $facade->read('data.enc');
echo $content;  // This is sensitive data

Laravel 中的 Facade

<?php
// Laravel Facade
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;

// 简单接口隐藏底层复杂性
Cache::put('key', 'value', 3600);
$value = Cache::get('key');

$users = DB::table('users')->where('active', 1)->get();

1.16 原型模式(Prototype)

目的:通过复制现有对象来创建新对象。

<?php
// 原型接口
interface PrototypeInterface
{
    public function clone(): self;
}

// 具体原型:简历
class Resume implements PrototypeInterface
{
    private $name;
    private $age;
    private $experience = [];
    
    public function __construct(string $name, int $age)
    {
        $this->name = $name;
        $this->age = $age;
    }
    
    public function addExperience(string $company, string $position)
    {
        $this->experience[] = [
            'company' => $company,
            'position' => $position
        ];
    }
    
    // 深拷贝
    public function clone(): self
    {
        $copy = new self($this->name, $this->age);
        $copy->experience = $this->experience;
        return $copy;
    }
    
    public function display()
    {
        echo "姓名: {$this->name}, 年龄: {$this->age}\n";
        foreach ($this->experience as $exp) {
            echo "- {$exp['company']}: {$exp['position']}\n";
        }
    }
}

// 使用:快速创建相似对象
$resume1 = new Resume('张三', 25);
$resume1->addExperience('A公司', 'PHP工程师');
$resume1->addExperience('B公司', '高级PHP工程师');

// 复制简历,修改部分信息
$resume2 = $resume1->clone();
$resume2->addExperience('C公司', '技术总监');

$resume1->display();
// 姓名: 张三, 年龄: 25
// - A公司: PHP工程师
// - B公司: 高级PHP工程师

$resume2->display();
// 姓名: 张三, 年龄: 25
// - A公司: PHP工程师
// - B公司: 高级PHP工程师
// - C公司: 技术总监

PHP 内置克隆

<?php
class Person
{
    public $name;
    public $address;
    
    public function __construct(string $name, Address $address)
    {
        $this->name = $name;
        $this->address = $address;
    }
    
    // 自定义克隆行为(深拷贝)
    public function __clone()
    {
        // 克隆引用类型属性
        $this->address = clone $this->address;
    }
}

class Address
{
    public function __construct(
        public string $city,
        public string $street
    ) {}
}

// 使用
$person1 = new Person('张三', new Address('北京', '朝阳区'));

// 浅拷贝(共享 Address 对象)
$person2 = clone $person1;
$person2->name = '李四';
$person2->address->city = '上海';  // 会影响 person1

// 深拷贝需要实现 __clone 方法

1.17 抽象工厂模式(Abstract Factory)

目的:提供一个创建一系列相关或相互依赖对象的接口。

<?php
// 抽象产品:按钮
interface ButtonInterface
{
    public function render(): string;
}

// 抽象产品:输入框
interface InputInterface
{
    public function render(): string;
}

// 具体产品:Windows按钮
class WindowsButton implements ButtonInterface
{
    public function render(): string
    {
        return '<button class="windows-btn">Windows按钮</button>';
    }
}

// 具体产品:Mac按钮
class MacButton implements ButtonInterface
{
    public function render(): string
    {
        return '<button class="mac-btn">Mac按钮</button>';
    }
}

// 具体产品:Windows输入框
class WindowsInput implements InputInterface
{
    public function render(): string
    {
        return '<input class="windows-input" />';
    }
}

// 具体产品:Mac输入框
class MacInput implements InputInterface
{
    public function render(): string
    {
        return '<input class="mac-input" />';
    }
}

// 抽象工厂
interface UIFactoryInterface
{
    public function createButton(): ButtonInterface;
    public function createInput(): InputInterface;
}

// 具体工厂:Windows UI
class WindowsUIFactory implements UIFactoryInterface
{
    public function createButton(): ButtonInterface
    {
        return new WindowsButton();
    }
    
    public function createInput(): InputInterface
    {
        return new WindowsInput();
    }
}

// 具体工厂:Mac UI
class MacUIFactory implements UIFactoryInterface
{
    public function createButton(): ButtonInterface
    {
        return new MacButton();
    }
    
    public function createInput(): InputInterface
    {
        return new MacInput();
    }
}

// 客户端代码
class Application
{
    private $factory;
    
    public function __construct(UIFactoryInterface $factory)
    {
        $this->factory = $factory;
    }
    
    public function render(): string
    {
        $button = $this->factory->createButton();
        $input = $this->factory->createInput();
        
        return $button->render() . "\n" . $input->render();
    }
}

// 使用
$windowsFactory = new WindowsUIFactory();
$app = new Application($windowsFactory);
echo $app->render();
// <button class="windows-btn">Windows按钮</button>
// <input class="windows-input" />

$macFactory = new MacUIFactory();
$app = new Application($macFactory);
echo $app->render();
// <button class="mac-btn">Mac按钮</button>
// <input class="mac-input" />

1.18 桥接模式(Bridge)

目的:将抽象部分与实现部分分离,使它们可以独立变化。

<?php
// 实现部分:消息发送器
interface MessageSenderInterface
{
    public function send(string $message): void;
}

// 具体实现:邮件发送
class EmailSender implements MessageSenderInterface
{
    public function send(string $message): void
    {
        echo "通过邮件发送: {$message}\n";
    }
}

// 具体实现:短信发送
class SmsSender implements MessageSenderInterface
{
    public function send(string $message): void
    {
        echo "通过短信发送: {$message}\n";
    }
}

// 具体实现:微信发送
class WechatSender implements MessageSenderInterface
{
    public function send(string $message): void
    {
        echo "通过微信发送: {$message}\n";
    }
}

// 抽象部分:通知
abstract class Notification
{
    protected $sender;
    
    public function __construct(MessageSenderInterface $sender)
    {
        $this->sender = $sender;
    }
    
    abstract public function notify(string $message): void;
}

// 扩展抽象:普通通知
class SimpleNotification extends Notification
{
    public function notify(string $message): void
    {
        $this->sender->send($message);
    }
}

// 扩展抽象:紧急通知
class UrgentNotification extends Notification
{
    public function notify(string $message): void
    {
        $this->sender->send("[紧急] " . $message);
    }
}

// 扩展抽象:定时通知
class ScheduledNotification extends Notification
{
    public function notify(string $message): void
    {
        $time = date('Y-m-d H:i:s');
        $this->sender->send("[{$time}] " . $message);
    }
}

// 使用:抽象和实现可以独立变化
$emailSender = new EmailSender();
$smsSender = new SmsSender();

// 邮件 + 普通通知
$notification1 = new SimpleNotification($emailSender);
$notification1->notify('你好');  // 通过邮件发送: 你好

// 短信 + 紧急通知
$notification2 = new UrgentNotification($smsSender);
$notification2->notify('系统故障');  // 通过短信发送: [紧急] 系统故障

// 微信 + 定时通知
$notification3 = new ScheduledNotification(new WechatSender());
$notification3->notify('会议提醒');  // 通过微信发送: [2025-10-28 10:00:00] 会议提醒

1.19 备忘录模式(Memento)

目的:在不破坏封装性的前提下,捕获对象的内部状态,并在该对象之外保存这个状态。

<?php
// 备忘录:保存编辑器状态
class EditorMemento
{
    private $content;
    private $cursorPosition;
    
    public function __construct(string $content, int $cursorPosition)
    {
        $this->content = $content;
        $this->cursorPosition = $cursorPosition;
    }
    
    public function getContent(): string
    {
        return $this->content;
    }
    
    public function getCursorPosition(): int
    {
        return $this->cursorPosition;
    }
}

// 发起人:编辑器
class TextEditor
{
    private $content = '';
    private $cursorPosition = 0;
    
    public function write(string $text)
    {
        $this->content .= $text;
        $this->cursorPosition += strlen($text);
    }
    
    public function getContent(): string
    {
        return $this->content;
    }
    
    // 创建备忘录
    public function save(): EditorMemento
    {
        return new EditorMemento($this->content, $this->cursorPosition);
    }
    
    // 从备忘录恢复
    public function restore(EditorMemento $memento)
    {
        $this->content = $memento->getContent();
        $this->cursorPosition = $memento->getCursorPosition();
    }
}

// 管理者:历史记录
class History
{
    private $mementos = [];
    
    public function push(EditorMemento $memento)
    {
        $this->mementos[] = $memento;
    }
    
    public function pop(): ?EditorMemento
    {
        if (empty($this->mementos)) {
            return null;
        }
        return array_pop($this->mementos);
    }
}

// 使用:支持撤销操作
$editor = new TextEditor();
$history = new History();

$editor->write('Hello ');
$history->push($editor->save());  // 保存状态

$editor->write('World');
$history->push($editor->save());  // 保存状态

$editor->write('!');
echo $editor->getContent();  // Hello World!

// 撤销
$memento = $history->pop();
$editor->restore($memento);
echo $editor->getContent();  // Hello World

// 再次撤销
$memento = $history->pop();
$editor->restore($memento);
echo $editor->getContent();  // Hello

1.20 访问者模式(Visitor)

目的:在不改变元素类的前提下,定义作用于这些元素的新操作。

<?php
// 访问者接口
interface ShapeVisitorInterface
{
    public function visitCircle(Circle $circle): void;
    public function visitRectangle(Rectangle $rectangle): void;
    public function visitTriangle(Triangle $triangle): void;
}

// 元素接口
interface ShapeInterface
{
    public function accept(ShapeVisitorInterface $visitor): void;
}

// 具体元素:圆形
class Circle implements ShapeInterface
{
    public function __construct(
        private float $radius
    ) {}
    
    public function getRadius(): float
    {
        return $this->radius;
    }
    
    public function accept(ShapeVisitorInterface $visitor): void
    {
        $visitor->visitCircle($this);
    }
}

// 具体元素:矩形
class Rectangle implements ShapeInterface
{
    public function __construct(
        private float $width,
        private float $height
    ) {}
    
    public function getWidth(): float
    {
        return $this->width;
    }
    
    public function getHeight(): float
    {
        return $this->height;
    }
    
    public function accept(ShapeVisitorInterface $visitor): void
    {
        $visitor->visitRectangle($this);
    }
}

// 具体元素:三角形
class Triangle implements ShapeInterface
{
    public function __construct(
        private float $base,
        private float $height
    ) {}
    
    public function getBase(): float
    {
        return $this->base;
    }
    
    public function getHeight(): float
    {
        return $this->height;
    }
    
    public function accept(ShapeVisitorInterface $visitor): void
    {
        $visitor->visitTriangle($this);
    }
}

// 具体访问者:计算面积
class AreaCalculator implements ShapeVisitorInterface
{
    private $totalArea = 0;
    
    public function visitCircle(Circle $circle): void
    {
        $area = pi() * pow($circle->getRadius(), 2);
        echo "圆形面积: {$area}\n";
        $this->totalArea += $area;
    }
    
    public function visitRectangle(Rectangle $rectangle): void
    {
        $area = $rectangle->getWidth() * $rectangle->getHeight();
        echo "矩形面积: {$area}\n";
        $this->totalArea += $area;
    }
    
    public function visitTriangle(Triangle $triangle): void
    {
        $area = ($triangle->getBase() * $triangle->getHeight()) / 2;
        echo "三角形面积: {$area}\n";
        $this->totalArea += $area;
    }
    
    public function getTotalArea(): float
    {
        return $this->totalArea;
    }
}

// 具体访问者:绘制图形
class ShapeRenderer implements ShapeVisitorInterface
{
    public function visitCircle(Circle $circle): void
    {
        echo "绘制圆形,半径: {$circle->getRadius()}\n";
    }
    
    public function visitRectangle(Rectangle $rectangle): void
    {
        echo "绘制矩形,宽: {$rectangle->getWidth()}, 高: {$rectangle->getHeight()}\n";
    }
    
    public function visitTriangle(Triangle $triangle): void
    {
        echo "绘制三角形,底: {$triangle->getBase()}, 高: {$triangle->getHeight()}\n";
    }
}

// 使用
$shapes = [
    new Circle(5),
    new Rectangle(4, 6),
    new Triangle(3, 4)
];

// 计算面积
$areaCalculator = new AreaCalculator();
foreach ($shapes as $shape) {
    $shape->accept($areaCalculator);
}
echo "总面积: {$areaCalculator->getTotalArea()}\n";

// 绘制图形
$renderer = new ShapeRenderer();
foreach ($shapes as $shape) {
    $shape->accept($renderer);
}

1.21 设计模式总结

创建型模式(5种)
模式目的使用场景Hyperf应用
单例只有一个实例配置、日志、数据库连接DI容器默认单例
工厂封装对象创建支付方式、缓存驱动DriverFactory
抽象工厂创建相关对象族UI组件、数据库驱动-
建造者分步骤构建对象SQL查询、配置构建QueryBuilder
原型复制对象对象克隆、原型实例-
结构型模式(7种)
模式目的使用场景Hyperf应用
适配器接口转换旧系统集成、第三方库-
装饰器动态添加功能日志、缓存、权限中间件
代理控制访问延迟加载、权限控制AOP代理
门面简化接口子系统封装Facade
桥接抽象与实现分离多维度变化-
组合树形结构菜单、文件系统-
享元共享对象大量相似对象-
行为型模式(11种)
模式目的使用场景Hyperf应用
策略算法可替换折扣计算、排序算法-
观察者一对多依赖事件监听、订阅Event系统
命令请求封装撤销重做、任务队列AsyncQueue
状态状态改变行为订单状态、工作流-
责任链链式处理过滤器、中间件Middleware
模板方法算法骨架数据导出、流程控制-
迭代器遍历集合集合遍历Iterator
备忘录保存恢复状态撤销功能、快照-
访问者操作与结构分离AST处理、报表生成-
中介者对象间解耦聊天室、调度中心-
解释器语法解析表达式求值、规则引擎-

2. 反射(Reflection)

2.1 什么是反射?

反射:在运行时分析类、方法、属性的能力。

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

// 反射类
$reflector = new ReflectionClass(User::class);

// 获取类名
echo $reflector->getName();  // User

// 获取所有属性
$properties = $reflector->getProperties();
foreach ($properties as $property) {
    echo $property->getName() . "\n";  // name, email
}

// 获取所有方法
$methods = $reflector->getMethods();
foreach ($methods as $method) {
    echo $method->getName() . "\n";  // __construct, getName
}

// 获取构造函数
$constructor = $reflector->getConstructor();
$parameters = $constructor->getParameters();

foreach ($parameters as $param) {
    echo $param->getName() . "\n";  // name, email
}

// 创建对象
$user = $reflector->newInstanceArgs(['张三', 'zhang@example.com']);

2.2 读取属性(Attributes)

<?php
use Attribute;

#[Attribute(Attribute::TARGET_CLASS)]
class Table
{
    public function __construct(public string $name)
    {
    }
}

#[Attribute(Attribute::TARGET_PROPERTY)]
class Column
{
    public function __construct(public string $name, public string $type = 'varchar')
    {
    }
}

#[Table('users')]
class User
{
    #[Column('user_name', 'varchar')]
    private $name;
    
    #[Column('user_email', 'varchar')]
    private $email;
    
    #[Column('user_age', 'int')]
    private $age;
}

// 读取属性
$reflector = new ReflectionClass(User::class);

// 读取类的属性
$tableAttributes = $reflector->getAttributes(Table::class);
foreach ($tableAttributes as $attr) {
    $table = $attr->newInstance();
    echo "表名:{$table->name}\n";  // users
}

// 读取属性的属性
$properties = $reflector->getProperties();
foreach ($properties as $property) {
    $columnAttributes = $property->getAttributes(Column::class);
    
    foreach ($columnAttributes as $attr) {
        $column = $attr->newInstance();
        echo "字段:{$column->name},类型:{$column->type}\n";
    }
}

// 输出:
// 表名:users
// 字段:user_name,类型:varchar
// 字段:user_email,类型:varchar
// 字段:user_age,类型:int

Hyperf 使用反射

  • 扫描注解(Attributes)
  • 自动注入依赖
  • 生成代理类(AOP)

3. 闭包(Closure)

3.1 什么是闭包?

闭包:匿名函数,可以捕获外部变量。

<?php
// 普通函数
function add($a, $b)
{
    return $a + $b;
}

// 闭包(匿名函数)
$add = function ($a, $b) {
    return $a + $b;
};

echo $add(1, 2);  // 3

// 闭包作为参数
function calculate($a, $b, $callback)
{
    return $callback($a, $b);
}

echo calculate(10, 20, function ($a, $b) {
    return $a + $b;
});  // 30

echo calculate(10, 20, function ($a, $b) {
    return $a * $b;
});  // 200

3.2 use 关键字(捕获外部变量)

<?php
$tax = 0.1;  // 外部变量

// 使用 use 捕获外部变量
$calculatePrice = function ($price) use ($tax) {
    return $price * (1 + $tax);
};

echo $calculatePrice(100);  // 110

// 捕获多个变量
$discount = 0.9;
$finalPrice = function ($price) use ($tax, $discount) {
    return $price * (1 + $tax) * $discount;
};

echo $finalPrice(100);  // 99

3.3 闭包的引用传递

<?php
$count = 0;

// 值传递:修改不影响外部变量
$increment1 = function () use ($count) {
    $count++;
    echo "闭包内:{$count}\n";
};

$increment1();  // 闭包内:1
echo "外部:{$count}\n";  // 外部:0(未改变)

// 引用传递:修改会影响外部变量
$increment2 = function () use (&$count) {  // 使用 &
    $count++;
    echo "闭包内:{$count}\n";
};

$increment2();  // 闭包内:1
echo "外部:{$count}\n";  // 外部:1(已改变)

3.4 箭头函数(PHP 7.4+)

<?php
$tax = 0.1;

// 传统闭包
$calculatePrice1 = function ($price) use ($tax) {
    return $price * (1 + $tax);
};

// 箭头函数(自动捕获外部变量)
$calculatePrice2 = fn($price) => $price * (1 + $tax);

echo $calculatePrice2(100);  // 110

// 数组操作
$numbers = [1, 2, 3, 4, 5];

// 传统方式
$doubled1 = array_map(function ($n) {
    return $n * 2;
}, $numbers);

// 箭头函数(更简洁)
$doubled2 = array_map(fn($n) => $n * 2, $numbers);

4. 生成器(Generator)

4.1 什么是生成器?

生成器:使用 yield 关键字,可以暂停和恢复函数执行,节省内存。

<?php
// 普通函数:一次性返回所有数据
function getNumbers()
{
    $numbers = [];
    for ($i = 1; $i <= 1000000; $i++) {
        $numbers[] = $i;
    }
    return $numbers;  // 内存占用:几百 MB
}

// 生成器:逐个返回数据
function generateNumbers()
{
    for ($i = 1; $i <= 1000000; $i++) {
        yield $i;  // 每次只返回一个值
    }
    // 内存占用:几 KB
}

// 使用生成器
foreach (generateNumbers() as $number) {
    echo $number . "\n";
    
    if ($number >= 10) {
        break;  // 可以提前退出
    }
}

4.2 生成器与数组的对比

<?php
// 方式一:返回数组(内存占用大)
function readLargeFile($filename)
{
    $lines = [];
    $handle = fopen($filename, 'r');
    
    while (!feof($handle)) {
        $lines[] = fgets($handle);  // 所有行都存到数组中
    }
    
    fclose($handle);
    return $lines;  // 如果文件 1GB,内存也要 1GB
}

// 方式二:使用生成器(内存占用小)
function readLargeFileGenerator($filename)
{
    $handle = fopen($filename, 'r');
    
    while (!feof($handle)) {
        yield fgets($handle);  // 逐行返回
    }
    
    fclose($handle);  // 内存占用:几 KB
}

// 使用
foreach (readLargeFileGenerator('large.txt') as $line) {
    echo $line;
}

4.3 生成器发送值

<?php
function printer()
{
    while (true) {
        $value = yield;  // 接收外部发送的值
        echo "收到:{$value}\n";
    }
}

$gen = printer();
$gen->next();  // 启动生成器

$gen->send('Hello');   // 收到:Hello
$gen->send('World');   // 收到:World

5. 异常处理

5.1 基本异常处理

<?php
try {
    // 可能抛出异常的代码
    $user = User::findOrFail(999);
} catch (ModelNotFoundException $e) {
    // 捕获特定异常
    echo "用户不存在\n";
} catch (\Exception $e) {
    // 捕获所有其他异常
    echo "发生错误:" . $e->getMessage();
} finally {
    // 无论是否发生异常都会执行
    echo "执行清理工作\n";
}

5.2 自定义异常

<?php
// 自定义异常类
class InsufficientBalanceException extends \Exception
{
    public function __construct($balance, $amount)
    {
        $message = "余额不足:当前余额 {$balance},需要 {$amount}";
        parent::__construct($message, 1001);
    }
}

class PaymentService
{
    public function pay($userId, $amount)
    {
        $balance = $this->getBalance($userId);
        
        if ($balance < $amount) {
            throw new InsufficientBalanceException($balance, $amount);
        }
        
        // 扣款
        $this->deduct($userId, $amount);
    }
}

// 使用
try {
    $paymentService->pay(1, 1000);
} catch (InsufficientBalanceException $e) {
    echo $e->getMessage();  // 余额不足:当前余额 500,需要 1000
    echo $e->getCode();     // 1001
}

5.3 异常层级

<?php
// 基础异常
class AppException extends \Exception {}

// 业务异常
class BusinessException extends AppException {}
class ValidationException extends BusinessException {}
class NotFoundException extends BusinessException {}

// 系统异常
class SystemException extends AppException {}
class DatabaseException extends SystemException {}
class CacheException extends SystemException {}

// 使用
try {
    // 业务逻辑
} catch (ValidationException $e) {
    // 处理验证异常
} catch (BusinessException $e) {
    // 处理其他业务异常
} catch (SystemException $e) {
    // 处理系统异常
} catch (AppException $e) {
    // 处理所有应用异常
}

6. 类型系统进阶

6.1 可空类型(Nullable)

<?php
class UserService
{
    // 返回值可以是 User 或 null
    public function getUserById(int $id): ?User
    {
        return User::find($id);
    }
    
    // 参数可以是 string 或 null
    public function search(?string $keyword): array
    {
        if ($keyword === null) {
            return User::all();
        }
        
        return User::where('name', 'like', "%{$keyword}%")->get();
    }
}

6.2 联合类型(PHP 8.0+)

<?php
class DataService
{
    // 参数可以是 int 或 string
    public function getId(int|string $id): int|string
    {
        return $id;
    }
    
    // 返回 array 或 null
    public function getData(): array|null
    {
        return ['data'];
    }
}

6.3 Mixed 类型(PHP 8.0+)

<?php
class CacheService
{
    // mixed:可以是任何类型
    public function get(string $key): mixed
    {
        return $this->redis->get($key);
    }
    
    public function set(string $key, mixed $value): bool
    {
        return $this->redis->set($key, $value);
    }
}

6.4 Void 类型

<?php
class LogService
{
    // void:没有返回值
    public function log(string $message): void
    {
        echo $message;
        // 不能有 return 语句(或只能 return;)
    }
}

7. 最佳实践

7.1 SOLID 原则

S - 单一职责原则(Single Responsibility)

一个类只负责一个功能。

<?php
// ❌ 违反单一职责
class User
{
    public function save() { /* 保存用户 */ }
    public function sendEmail() { /* 发送邮件 */ }
    public function log() { /* 记录日志 */ }
}

// ✅ 遵守单一职责
class User
{
    public function save() { /* 保存用户 */ }
}

class EmailService
{
    public function send() { /* 发送邮件 */ }
}

class Logger
{
    public function log() { /* 记录日志 */ }
}
O - 开闭原则(Open-Closed)

对扩展开放,对修改关闭。

<?php
// ❌ 违反开闭原则:新增支付方式需要修改代码
class PaymentService
{
    public function pay($type, $amount)
    {
        if ($type === 'alipay') {
            // 支付宝支付
        } elseif ($type === 'wechat') {
            // 微信支付
        } elseif ($type === 'credit_card') {  // 新增支付方式,需要修改这里
            // 信用卡支付
        }
    }
}

// ✅ 遵守开闭原则:新增支付方式无需修改代码
interface PaymentInterface
{
    public function pay($amount);
}

class PaymentService
{
    public function pay(PaymentInterface $payment, $amount)
    {
        $payment->pay($amount);  // 无需修改
    }
}

// 新增支付方式:只需创建新类
class CreditCardPayment implements PaymentInterface
{
    public function pay($amount)
    {
        // 信用卡支付
    }
}
L - 里氏替换原则(Liskov Substitution)

子类可以替换父类。

<?php
class Bird
{
    public function fly()
    {
        echo "鸟在飞\n";
    }
}

// ❌ 违反里氏替换原则:企鹅不会飞
class Penguin extends Bird
{
    public function fly()
    {
        throw new \Exception('企鹅不会飞');
    }
}

// ✅ 正确设计
interface Flyable
{
    public function fly();
}

class Bird implements Flyable
{
    public function fly()
    {
        echo "鸟在飞\n";
    }
}

class Penguin  // 企鹅不实现 Flyable
{
    public function swim()
    {
        echo "企鹅在游泳\n";
    }
}
I - 接口隔离原则(Interface Segregation)

不要强迫类实现不需要的方法。

<?php
// ❌ 违反接口隔离原则
interface Worker
{
    public function work();
    public function eat();
    public function sleep();
}

class Robot implements Worker
{
    public function work() { /* 工作 */ }
    public function eat() { /* 机器人不需要吃饭 */ }
    public function sleep() { /* 机器人不需要睡觉 */ }
}

// ✅ 遵守接口隔离原则
interface Workable
{
    public function work();
}

interface Eatable
{
    public function eat();
}

interface Sleepable
{
    public function sleep();
}

class Human implements Workable, Eatable, Sleepable
{
    public function work() { /* 工作 */ }
    public function eat() { /* 吃饭 */ }
    public function sleep() { /* 睡觉 */ }
}

class Robot implements Workable
{
    public function work() { /* 工作 */ }
    // 不需要实现 eat 和 sleep
}
D - 依赖倒置原则(Dependency Inversion)

依赖接口,而不是具体实现。

<?php
// ❌ 违反依赖倒置原则:依赖具体实现
class UserController
{
    private $userService;
    
    public function __construct()
    {
        $this->userService = new UserService();  // 依赖具体类
    }
}

// ✅ 遵守依赖倒置原则:依赖接口
class UserController
{
    private $userService;
    
    public function __construct(UserServiceInterface $userService)
    {
        $this->userService = $userService;  // 依赖接口
    }
}

8. 要点

必须掌握

  • 常用设计模式(单例、工厂、策略)
  • 反射的基本使用
  • 闭包和箭头函数
  • 生成器的优势
  • SOLID 原则

加分项

  • 观察者模式的应用
  • DI 容器的实现原理
  • 更多设计模式(装饰器、适配器、代理等)

高频题

1. 什么是单例模式?如何实现?

答:单例模式确保一个类只有一个实例。

实现要点:

  1. 私有构造函数,防止 new
  2. 私有克隆方法,防止 clone
  3. 静态方法获取实例

2. 工厂模式有什么用?

答:工厂模式用于创建对象,隐藏创建逻辑。

优势:

  • 创建逻辑集中管理
  • 使用者不需要知道具体类
  • 便于扩展新类型

3. 生成器有什么优势?

答:生成器使用 yield 逐个返回数据,节省内存。

优势:

  • 内存占用小(不需要一次性加载所有数据)
  • 可以处理无限序列
  • 适合处理大文件、大数据集

4. SOLID 原则是什么?

答:

  • S:单一职责原则 - 一个类只负责一个功能
  • O:开闭原则 - 对扩展开放,对修改关闭
  • L:里氏替换原则 - 子类可以替换父类
  • I:接口隔离原则 - 不要强迫类实现不需要的方法
  • D:依赖倒置原则 - 依赖接口,而不是具体实现

下一步:阅读 01-核心概念.md 开始学习 Hyperf