PHP递归对象创建引发内存耗尽,能否实现循环引用对象?
循环引用对象结构的实现方法(解决内存耗尽问题)
你的代码之所以触发Fatal error: Allowed memory size of X bytes exhausted,核心原因是构造函数里的无限递归实例化:当你创建AA的实例时,它的构造函数会创建BB的实例;而BB的构造函数又会反过来创建AA的实例,这个过程无限重复,不断创建新对象占用内存,直到达到PHP的内存限制。
但你想要的循环引用对象结构(Universe→Galaxy→Blackhole→Whitehole→Universe)是完全可以实现的,只要避开这种无限递归的创建方式就行。下面给你两种可行的实现思路:
方法一:先创建所有对象,再手动关联引用
这种方式最直观,先逐个创建每个类的实例,最后再把循环的引用关系赋值上。因为PHP中对象是按引用传递的,赋值时不会创建新实例,只会指向已存在的对象,所以不会触发无限递归。
示例代码:
class Universe { public $galaxies = []; // 存储多个Galaxy } class Galaxy { public $blackhole; // 关联一个Blackhole public $stars = []; // 存储多个Star } class Blackhole { public $whitehole; // 关联一个Whitehole } class Whitehole { public $universe; // 关联回Universe } // 逐步构建对象结构 $universe = new Universe(); // 创建Galaxy并加入Universe $milkyWay = new Galaxy(); $universe->galaxies[] = $milkyWay; // 创建Blackhole并关联到Galaxy $sagA = new Blackhole(); $milkyWay->blackhole = $sagA; // 创建Whitehole,先关联到Blackhole,再把Universe关联回Whitehole $whitehole = new Whitehole(); $sagA->whitehole = $whitehole; $whitehole->universe = $universe; // 验证循环引用是否生效 var_dump($whitehole->universe->galaxies[0]->blackhole->whitehole === $whitehole); // 输出:bool(true),说明循环引用已正确建立
方法二:通过构造函数参数传递已存在的对象
如果你希望在构造函数中完成部分关联逻辑,可以通过构造函数参数把已创建的上级对象传递进去,避免在构造函数中重新创建会触发循环的对象。
示例代码:
class Universe { public $galaxies = []; public function addGalaxy(Galaxy $galaxy) { $this->galaxies[] = $galaxy; } } class Galaxy { public $blackhole; public $stars = []; private $universe; public function __construct(Universe $universe) { $this->universe = $universe; // 创建Blackhole时把当前Galaxy实例传进去 $this->blackhole = new Blackhole($this); } // 给Blackhole提供获取Universe的方法 public function getUniverse(): Universe { return $this->universe; } } class Blackhole { public $whitehole; private $galaxy; public function __construct(Galaxy $galaxy) { $this->galaxy = $galaxy; // 创建Whitehole时传入已存在的Universe实例 $this->whitehole = new Whitehole($galaxy->getUniverse()); } } class Whitehole { public $universe; public function __construct(Universe $universe) { $this->universe = $universe; } } // 使用方式 $universe = new Universe(); $milkyWay = new Galaxy($universe); $universe->addGalaxy($milkyWay); // 验证循环引用 var_dump($milkyWay->blackhole->whitehole->universe === $universe); // 输出:bool(true)
关键要点总结
- PHP完全支持对象的循环引用,不需要额外配置;
- 避免在构造函数中递归创建新的循环对象实例,这是导致内存耗尽的核心原因;
- 构建循环关系时,始终引用已存在的对象实例,而不是新建。
内容的提问来源于stack exchange,提问作者DonJoe
相关产品推荐
相关产品推荐

