PHP代理模式核心在于控制访问行为而非对象,须通过接口定义契约以保障类型安全;真实对象应依赖注入或工厂获取,支持懒加载;缓存与日志代理职责分离,不可强行抽象;拦截层级决定架构质量。

PHP 代理模式不是靠魔术方法硬凑出来的,核心在于「控制访问」——你要代理的是行为,不是对象本身。
什么时候该用 __call(),什么时候该手动定义接口
直接在代理类里写 __call() 看似省事,但会丢失类型提示、IDE 跳转和静态分析能力。真正需要代理的场景(比如远程服务、权限校验、缓存封装)往往有明确契约,这时必须先定义接口:
- 被代理对象和代理类都实现同一接口,调用方只依赖接口,不感知代理存在
- 接口方法名、参数、返回值类型清晰,PHP 8+ 的联合类型和返回类型声明能立刻暴露不一致
-
__call()只适合调试桥接或极简原型,上线项目中它会让phpstan报一堆Call to an undefined method
代理类里调用真实对象时,别直接 new 实例
硬编码 new RealSubject() 会让代理失去解耦意义。常见错误是把代理写成“增强版包装器”,结果真实对象生命周期失控:
- 用构造函数注入真实对象实例,或通过工厂/容器获取 —— 这样才能控制其创建时机和作用域(比如单例 or 每次新建)
- 如果真实对象初始化开销大(如连接数据库),代理里应延迟初始化,在第一次调用时才创建(即「懒加载代理」)
- 注意循环引用:代理持有了真实对象,而真实对象又反向持有代理(比如回调注册),会导致
gc_collect_cycles()失效或内存泄漏
缓存代理和日志代理不能共用一个基类
看似都是“加一层逻辑”,但它们的职责和副作用完全不同:
- 缓存代理必须判断方法是否幂等(
get*/find*可缓存,save*不行),还要处理 TTL、键生成、缓存穿透防护 - 日志代理关注执行耗时、入参脱敏、异常捕获,但绝不能影响原方法返回值或抛出异常的语义
- 强行抽象成
AbstractProxy并塞进$this->before()/$this->after()钩子,最后会变成状态混乱的“瑞士军刀”,改一处就崩三处
代理最难的从来不是写法,而是决定“在哪一层拦截”——是 HTTP 入口做网关代理?还是领域层对仓储接口做缓存代理?选错层级,代码越写越重,问题越藏越深。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











