128 mégaoctets consommés pour traiter trois mille articles : c’est le constat qui a mené à revoir un traitement d’export dans une extension éditoriale. Le code parcourait une liste de WP_Post, calculait un score de lisibilité coûteux pour chacun, et mémorisait ce score dans un tableau PHP indexé par identifiant d’article pour éviter de le recalculer si le même post repassait dans une boucle imbriquée plus loin dans le traitement.
Le problème ne venait pas du calcul lui-même, mais du tableau de mémorisation : en conservant l’identifiant de chaque article, ce tableau grossissait indéfiniment sur toute la durée du script, sans jamais être nettoyé, même une fois le traitement d’un article terminé. Sur un grand export, la consommation mémoire montait en flèche pour un gain de performance qui, au fond, n’avait besoin d’exister que le temps du traitement d’un seul article.
Le tableau associatif classique, et sa limite
La version initiale ressemblait à ceci : un tableau PHP simple, indexé par l’identifiant du post, qui sert de cache de calcul le temps de la boucle.
$scores_lisibilite = array();
foreach ( $articles as $article ) {
if ( ! isset( $scores_lisibilite[ $article->ID ] ) ) {
$scores_lisibilite[ $article->ID ] = calculer_score_lisibilite( $article->post_content );
}
traiter_article( $article, $scores_lisibilite[ $article->ID ] );
}
Ce code fonctionne, mais le tableau $scores_lisibilite reste entièrement en mémoire jusqu’à la fin du script, même pour des articles déjà traités et qui ne seront plus jamais consultés. Sur un traitement de plusieurs dizaines de milliers d’articles, cette accumulation devient significative, surtout si l’objet WP_Post associé transporte lui-même un contenu volumineux.
Ce qu’apporte la classe WeakMap

PHP 8.0 introduit la classe WeakMap, qui permet d’associer une donnée à un objet sans empêcher le ramasse-miettes de libérer cet objet dès qu’il n’existe plus de référence forte ailleurs dans le script. Contrairement à un tableau indexé par identifiant, une WeakMap utilise l’objet lui-même comme clé, et l’entrée disparaît automatiquement quand cet objet est détruit.
$scores_lisibilite = new WeakMap();
foreach ( $articles as $article ) {
if ( ! isset( $scores_lisibilite[ $article ] ) ) {
$scores_lisibilite[ $article ] = calculer_score_lisibilite( $article->post_content );
}
traiter_article( $article, $scores_lisibilite[ $article ] );
unset( $article ); // dès qu'aucune autre référence ne subsiste, l'entrée est libérée
}
La différence essentielle tient dans la nature de la clé : ce n’est plus un entier stable qui s’accumule indéfiniment, mais l’objet WP_Post lui-même. Une fois que ce post sort de portée, la WeakMap ne le retient pas artificiellement en vie, et l’entrée correspondante disparaît d’elle-même.
Un piège à connaître : la source des objets WP_Post
Ce mécanisme ne fonctionne correctement que si les objets WP_Post traités sont bien des instances distinctes à chaque itération, et non des références vers un unique objet réutilisé. Avec get_posts() ou une boucle WP_Query classique, chaque itération fournit une instance propre, ce qui rend la WeakMap pertinente. Le comportement serait différent avec un objet global partagé et modifié en place.
Quand préférer un tableau simple malgré tout
La WeakMap n’est pas une solution universelle. Si la donnée associée doit survivre au-delà de la requête ou être partagée entre plusieurs traitements successifs, un tableau classique, voire un transient ou une table dédiée, reste plus approprié. La WeakMap répond spécifiquement au cas d’un état de calcul strictement temporaire, borné à la durée de vie de l’objet auquel il se rattache.
- Utiliser
WeakMappour un cache de calcul local à une boucle de traitement, jamais pour une donnée qui doit persister. - Vérifier que les objets utilisés comme clés sont bien des instances distinctes, pas un objet global réutilisé.
- Ne pas confondre avec
WeakReference, une classe complémentaire qui référence un objet unique sans l’associer à une donnée.
Mesurer avant de généraliser
Sur le traitement d’export mentionné plus haut, remplacer le tableau associatif par une WeakMap a permis de stabiliser la consommation mémoire au lieu qu’elle grimpe linéairement avec le nombre d’articles traités. Le gain dépend directement du volume traité et du poids de la donnée associée : sur une poignée d’articles, la différence est négligeable.
Avant d’introduire une WeakMap dans un traitement critique, vérifiez avec
memory_get_peak_usage()que le tableau associatif est bien la cause du problème, et non le contenu des articles eux-mêmes.
En résumé
La classe WeakMap de PHP 8 répond à un besoin précis : associer une donnée temporaire à un objet sans empêcher son ramasse-miettes naturel. Ce n’est pas un mécanisme de mise en cache persistante, mais un outil de maîtrise mémoire pour des traitements en boucle où un tableau indexé par identifiant deviendrait, avec le temps, une fuite mémoire déguisée en optimisation.