PHP 7.3 中无法使用 WeakReference,需通过设计规避循环引用:手动置 null 断开强引用、改用 setter 注入、以 ID 替代对象引用、分批处理并及时 unset。

PHP 7.3 中没有 WeakReference(该特性从 PHP 7.4 才引入),因此无法用弱引用来自然破环。但循环引用仍可有效规避,关键在于**不依赖语言新特性,而靠设计控制和主动管理**。
手动切断引用关系
这是 PHP 7.3 下最直接、最可控的解法。只要对象间强引用被显式置为 null,引用计数就能归零,内存立即释放。
- 在子对象中避免直接保存父对象实例,如
$this->parent = $parent; - 若必须持有,定义清理方法(如
tearDown()),在业务结束前统一调用:$child->tearDown(); $parent->tearDown(); - 清理方法内将双向属性全部设为
null,再配合unset($parent, $child)
改用 setter 注入替代构造注入
构造函数互相依赖会导致初始化失败或无限递归,尤其在 DI 容器中极易触发死锁。PHP 7.3 完全支持类型声明与可空类型(?ClassB),适合安全使用 setter 模式。
- 把
public function __construct(ClassB $b)改为私有属性 + 公共 setter - 确保所有 setter 调用在对象真正使用前完成,避免运行时
Call to a member function on null - 配合 PHPStan 等工具可静态检测未初始化属性调用
用 ID 或标识符代替对象引用
当逻辑上需要“关联”而非“持有”,就不要传对象,传 ID。真正要用时再查——这既打破循环,又符合单一职责。
立即学习“PHP免费学习笔记(深入)”;
- 例如:不写
$post->author = $author;,而写$post->author_id = $author->id; - 访问作者时调用
$authorRepo->findById($post->author_id) - ORM 场景下,Doctrine 或 Eloquent 默认就是这种懒加载/代理思路
分批处理并及时 unset
对批量操作(如遍历大量记录并构建对象图),避免一次性加载全部对象形成复杂引用网。
- 用
yield或数据库游标分页,每次只处理一小批 - 每轮结束后明确
unset($items),防止临时变量长期滞留 - 搭配
gc_collect_cycles()可加快已断引用的回收(虽非必需,但实测有效)



















