04-12-2025

Referencias circulares en php: qué son y cómo evitarlas

Las referencias circulares en php ocurren cuando dos o más objetos se referencian mutuamente, creando un ciclo que impide que el recolector de basura los libere de memoria, incluso cuando ya no son necesarios para el programa. Ejemplo sencillo de referencia circular:

class Persona {
public $amigo = null;
}

$juan = new Persona();
$maria = new Persona();

$juan->amigo = $maria;// Juan apunta a María
$maria->amigo = $juan;// María apunta de vuelta a Juan

$juan = null;//Se ntentan liberar los objetos
$maria = null;
En el ejemplo anterior, aunque se pone a "$juan" y "$maria" a "null", los objetos siguen existiendo en memoria porque el "objeto de Juan"" tiene una referencia al "objeto de "María"".
El "objeto de María" tiene una referencia al "objeto de Juan"→ Se forma un ciclo → El contador de referencias de ambos objetos nunca llega a 0. Antes de php 5.3, esto provocaba fugas de memoria (memory leaks) graves.h2 style="color:#333; border-bottom:2px solid #0a5; padding-bottom:8px; margin:40px 0 20px;">Cómo evitar o romper referencias circulares
  • Poner propiedades a null manualmente al destruir objetos.

    public function __destruct() {
    $this->amigo = null;
    $this->padre = null;
    foreach ($this->hijos as $hijo) {
    $hijo->padre = null;
    }
    }
    
  • Usar WeakMap.

    $map = new WeakMap();
    $obj = new stdClass();
    $map[$obj] = 'datos';  // No impide que $obj sea recolectado
    
  • Usar IDs en vez de objetos en relaciones bidireccionales.

    class Usuario {
    public $amigosIds = [];  // Solo guarda IDs
    // en vez de guardar objetos Usuario directamente
    }
    
En la práctica, en aplicaciones normales no es necesario preocuparse mucho por las referencias circulares gracias al garbage collector de PHP, pero en aplicaciones muy intensivas en memoria o con estructuras complejas (como árboles grandes, grafos, ORM con muchas relaciones), sí es importante conocerlas y saber romper los ciclos cuando sea necesario.