Uso Eficiente de Memoria en PHP con WeakMaps

En el desarrollo web, manejar bien la memoria puede marcar la diferencia en el rendimiento de una aplicación. En PHP, hay una estructura de datos que suele pasar desapercibida pero que resulta útil para este propósito: el WeakMap.
En este artículo explico qué es un WeakMap, cómo se diferencia de un array común y en qué situaciones conviene usarlo.
¿Qué es un WeakMap?:
Un WeakMap, disponible desde PHP 8.0, es una estructura de datos que nos permite asociar pares de llaves y valores, pero con una característica única: maneja las llaves como referencias débiles. Esto significa que si la única referencia a una llave está dentro del WeakMap, la llave será eliminada automáticamente de la memoria cuando ya no se utilice en ningún otro lugar del código.
Diferencias con un Array Normal:
Un array normal no sirve para esto: sus llaves solo pueden ser enteros o strings, así que no puedes usar un objeto como llave. La estructura con la que sí vale la pena comparar es SplObjectStorage, que también asocia datos a objetos pero guarda referencias fuertes: mientras el objeto esté en el storage, sigue vivo aunque ya no lo uses en ningún otro lugar. Un WeakMap, en cambio, elimina la entrada en cuanto el objeto deja de existir.
Ejemplo Práctico:
<?php
$weakMap = new WeakMap();
$objetoLlave = new stdClass();
$weakMap[$objetoLlave] = "Valor asociado";
echo $weakMap[$objetoLlave] . "\n";
echo "Entradas antes: " . count($weakMap) . "\n";
unset($objetoLlave);
echo "Entradas después: " . count($weakMap) . "\n";Al ejecutarlo me da los siguientes resultados:
Valor asociado
Entradas antes: 1
Entradas después: 0Ahorro de Memoria:
Para ver la diferencia en memoria, asociemos un valor a 100.000 objetos temporales: en cada vuelta del bucle se crea un objeto nuevo y el anterior deja de usarse. Lo hacemos una vez con WeakMap y otra con SplObjectStorage.
Ejemplo Práctico:
<?php
$sizeBefore = memory_get_usage();
$weakMap = new WeakMap();
for ($i = 0; $i < 100000; $i++) {
$objeto = new stdClass();
$weakMap[$objeto] = $i;
}
$sizeAfter = memory_get_usage();
echo "WeakMap: " . count($weakMap) . " entradas, " . ($sizeAfter - $sizeBefore) . " bytes\n";
$sizeBefore = memory_get_usage();
$storage = new SplObjectStorage();
for ($i = 0; $i < 100000; $i++) {
$objeto = new stdClass();
$storage[$objeto] = $i;
}
$sizeAfter = memory_get_usage();
echo "SplObjectStorage: " . count($storage) . " entradas, " . ($sizeAfter - $sizeBefore) . " bytes\n";Al ejecutarlo con PHP 8.4 me da los siguientes resultados:
WeakMap: 1 entradas, 776 bytes
SplObjectStorage: 100000 entradas, 12683408 bytesEl WeakMap termina con una sola entrada (el último objeto, que sigue vivo en $objeto) porque cada objeto anterior se liberó al reasignar la variable y su entrada desapareció con él. SplObjectStorage retiene los 100.000 objetos y sus valores. Las cifras exactas cambian según la versión de PHP y el equipo.
En resumen
Un WeakMap en PHP permite asociar datos a objetos sin impedir que el garbage collector los libere cuando ya no se necesitan. Esto lo hace útil en escenarios donde se trabaja con muchos objetos temporales, ya que evita el crecimiento innecesario del uso de memoria que sí ocurre con SplObjectStorage o con cualquier estructura que guarde referencias fuertes.
Otras piezas de PHP que se notan cuando el proyecto crece, en la guía de PHP.
Fuentes
- PHP: WeakMap - Manual (manual oficial de PHP)
- PHP RFC: Weak maps (RFC oficial de PHP)
- Nuevas características de PHP 8.0 (manual oficial de PHP)
- PHP: memory_get_usage - Manual (manual oficial de PHP)
¿Tienes un proyecto en mente?
Trabajo con Laravel, WordPress, SEO técnico y servidores MCP. El primer paso es una llamada de descubrimiento, sin costo ni compromiso, donde me cuentas qué necesitas y te digo con honestidad si puedo ayudarte.