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. 什么是单例模式?如何实现?
答:单例模式确保一个类只有一个实例。
实现要点:
- 私有构造函数,防止 new
- 私有克隆方法,防止 clone
- 静态方法获取实例
2. 工厂模式有什么用?
答:工厂模式用于创建对象,隐藏创建逻辑。
优势:
- 创建逻辑集中管理
- 使用者不需要知道具体类
- 便于扩展新类型
3. 生成器有什么优势?
答:生成器使用 yield 逐个返回数据,节省内存。
优势:
- 内存占用小(不需要一次性加载所有数据)
- 可以处理无限序列
- 适合处理大文件、大数据集
4. SOLID 原则是什么?
答:
- S:单一职责原则 - 一个类只负责一个功能
- O:开闭原则 - 对扩展开放,对修改关闭
- L:里氏替换原则 - 子类可以替换父类
- I:接口隔离原则 - 不要强迫类实现不需要的方法
- D:依赖倒置原则 - 依赖接口,而不是具体实现
下一步:阅读 01-核心概念.md 开始学习 Hyperf