Un panier, une liste de commandes ou un ensemble de règles métier finit souvent par devoir produire une seule valeur exploitable. En PHP, array_reduce() permet de parcourir un tableau et de construire progressivement ce résultat, qu’il s’agisse d’un total, d’un compteur ou même d’un nouveau tableau. Je détaille son fonctionnement, l’usage du callback, la valeur initiale, les erreurs fréquentes et les cas où une boucle classique reste préférable.
Une réduction bien initialisée rend le code plus clair et plus fiable
- Deux paramètres sont transmis au callback : l’accumulateur et l’élément courant.
- La valeur initiale définit le type et le point de départ du résultat.
- Un tableau vide renvoie l’initiale, ou null si elle n’est pas fournie.
- Le callback doit toujours retourner l’accumulateur mis à jour.
- Pour une logique complexe ou l’accès aux clés, foreach est parfois plus lisible.
Comprendre ce que réduit réellement array_reduce
La fonction prend un tableau, un callback et une valeur initiale facultative. À chaque passage, le callback reçoit la valeur accumulée jusque-là et l’élément courant. Son retour devient le nouvel accumulateur, jusqu’à obtenir une seule valeur finale.
$carry + $item,
0
);
echo $resultat; // 25
?>
Dans cet exemple, $carry commence à 0. Il devient 12 après le premier élément, puis 20 et enfin 25. Cette mécanique ressemble à un pliage successif, mais je la trouve surtout utile lorsque chaque élément doit enrichir un état clairement défini.
| Élément | Rôle | Exemple |
|---|---|---|
$array |
Tableau parcouru | [12, 8, 5] |
$callback |
Règle appliquée à chaque passage | fn($carry, $item) => $carry + $item |
$initial |
Point de départ du calcul | 0 |
Le callback reçoit la valeur courante, mais pas la clé du tableau. Si vous avez besoin de la clé, une boucle foreach est souvent la solution la plus directe. La documentation officielle de PHP confirme également que la valeur initiale sert de résultat pour un tableau vide.
Écrire un callback fiable dès le premier passage
La valeur initiale n’est pas un simple détail syntaxique. Elle représente l’élément neutre de votre opération : 0 pour une addition, 1 pour une multiplication, une chaîne vide pour une concaténation ou un tableau vide pour une agrégation.
$carry + $item,
0.0
);
echo number_format($total, 2, ',', ' '); // 37,40
?>
Sans troisième argument, PHP démarre le callback avec null. Une addition peut sembler fonctionner grâce à la conversion implicite, mais ce comportement devient piégeux avec les booléens, les chaînes ou les objets. Pour un code durable, je préfère toujours exprimer explicitement l’état initial.
Le cas du tableau vide mérite la même attention. Avec array_reduce([], $callback, 0), le résultat est 0. Sans valeur initiale, le résultat est null, ce qui peut provoquer une erreur plus loin dans le traitement ou produire une réponse JSON inattendue.
Autre règle non négociable : le callback doit retourner l’accumulateur. Une fonction qui modifie une variable mais ne renvoie rien transforme le résultat en null dès le premier tour. Depuis PHP 8, un callback qui attend un paramètre par référence déclenche également un avertissement, ce qui rend cette approche encore moins intéressante.
Des exemples utiles en développement web
Calculer un total de commande
Pour une commande, l’accumulateur peut contenir plusieurs informations à la fois. Cette technique évite de multiplier les parcours du tableau lorsque le nombre d’articles, le sous-total et la quantité totale doivent être calculés ensemble.
'Clavier', 'prix' => 49.90, 'quantite' => 1],
['nom' => 'Souris', 'prix' => 24.90, 'quantite' => 2],
];
$commande = array_reduce(
$articles,
function ($carry, $article) {
$carry['quantite'] += $article['quantite'];
$carry['total'] += $article['prix'] * $article['quantite'];
return $carry;
},
['quantite' => 0, 'total' => 0.0]
);
print_r($commande);
?>
Le résultat contient ici une quantité totale de 3 et un montant de 99,70. Pour de vrais calculs financiers, je recommande toutefois de travailler en centimes entiers ou avec une bibliothèque adaptée afin d’éviter les effets de précision des nombres flottants.
Regrouper des éléments par catégorie
Un autre usage courant consiste à transformer une liste plate en structure organisée. C’est pratique pour préparer des données destinées à une vue, une API ou un menu d’administration.
'Clavier', 'categorie' => 'bureau'],
['nom' => 'Lampe', 'categorie' => 'bureau'],
['nom' => 'Casque', 'categorie' => 'audio'],
];
$parCategorie = array_reduce(
$produits,
function ($carry, $produit) {
$categorie = $produit['categorie'];
$carry[$categorie][] = $produit['nom'];
return $carry;
},
[]
);
print_r($parCategorie);
?>
La valeur initiale est un tableau vide, car le résultat final doit rester un tableau. Le point important est de toujours retourner la nouvelle structure complète à chaque itération.
Compter des statuts
Pour une interface de suivi, on peut aussi réduire une liste d’enregistrements en indicateurs rapides. Le résultat sera directement utilisable pour afficher des badges ou des compteurs.
'payee'],
['statut' => 'en_attente'],
['statut' => 'payee'],
];
$compteurs = array_reduce(
$commandes,
function ($carry, $commande) {
$statut = $commande['statut'];
$carry[$statut] = ($carry[$statut] ?? 0) + 1;
return $carry;
},
[]
);
print_r($compteurs);
?>
Cette forme est concise, mais elle suppose que chaque élément possède bien une clé statut. Dans une application exposée à des données utilisateur ou à une réponse externe, je valide ce format avant la réduction.
Choisir entre array_reduce et une boucle foreach
La réduction est élégante quand l’opération tient dans une règle simple et que le résultat se lit immédiatement. Elle devient moins confortable dès que le callback contient plusieurs conditions, des effets de bord ou de nombreuses mutations internes.
| Solution | À privilégier pour | Limite principale |
|---|---|---|
array_reduce() |
Construire une valeur ou une structure à partir de tous les éléments | Le callback peut devenir difficile à lire |
foreach |
Accéder aux clés, gérer plusieurs branches ou interrompre le parcours | Un peu plus de code explicite |
array_sum() |
Additionner directement des valeurs numériques | Ne convient pas à une logique personnalisée |
array_map() puis array_filter()
|
Transformer ou filtrer sans maintenir un état complexe | Peut nécessiter plusieurs parcours |
Pour une simple somme, array_sum() est plus lisible. Pour parcourir un tableau associatif avec ses clés, je choisis généralement foreach. La performance reste souvent secondaire ici : la réduction parcourt les éléments en O(n), mais l’appel répété d’un callback et la construction de gros tableaux peuvent augmenter le coût réel.
Je déconseille aussi d’utiliser une réduction uniquement pour donner une apparence fonctionnelle à un traitement impératif. Si le lecteur doit décoder cinq conditions imbriquées pour comprendre le résultat, une boucle claire sera plus facile à tester et à maintenir.
Éviter les pièges qui rendent le résultat faux
Ne pas confondre valeur et clé
Le callback reçoit $carry et $item, pas la clé courante. Si les clés sont indispensables, vous pouvez réduire array_keys($tableau) et accéder au tableau d’origine, mais cette solution alourdit vite le code. Dans ce cas, foreach est plus transparent.
Vérifier les types avant le calcul
Une donnée vide, une chaîne non numérique ou un champ absent peut contaminer tout le résultat. Pour des données venant d’un formulaire ou d’une API, je préfère rejeter explicitement la valeur plutôt que de compter sur les conversions automatiques de PHP.
Lire aussi : PHP REST API - Construisez une API robuste et durable
Éviter les effets de bord
Le callback devrait produire un nouvel état à partir de l’ancien. Modifier des variables externes avec use, écrire dans une base de données ou envoyer un événement pendant la réduction rend le comportement plus difficile à prévoir. Je réserve ces actions à une étape séparée, après validation du résultat.
Enfin, testez au minimum trois scénarios : un tableau normal, un tableau vide et une donnée inattendue. Ces cas révèlent rapidement les erreurs d’initialisation et les retours implicites de null.
Le bon réflexe avant d’adopter array_reduce
Utilisez cette fonction lorsque vous pouvez expliquer en une phrase ce que devient l’accumulateur à chaque élément. Cette règle suffit souvent à distinguer une réduction élégante d’un callback trop chargé.
Pour additionner, comptez ou regrouper des données, choisissez une valeur initiale du bon type et retournez-la systématiquement. Pour une logique longue, l’accès aux clés ou un traitement qui doit s’arrêter en cours de route, une boucle foreach restera généralement le choix le plus lisible.
Bien employé, array_reduce() ne remplace pas toutes les boucles PHP. Il offre surtout une manière nette de transformer une collection en résultat unique, avec un comportement prévisible même lorsque le tableau est vide.