La fonction array_merge_recursive() n'agit pas vraiment comme on pourrait s'y attendre
La fonction array_merge_recursive() n'agit pas vraiment comme on pourrait s'y attendre. Au lieu de simplement combiner des tableaux associatifs, elle en crée de nouveaux pour toutes les valeurs aux clés identiques, même s'il s'agit de simples booléens ou chaines de caractères.
Prenons le cas tout simple de la combinaison de deux tableaux pour configurer un framework génial :
<?php
array_merge_recursive
(
array('cache modules' => false),
array('cache modules' => true)
)
?>
array_merge_recursive renverra le tableau suivant :
array
'cache modules' =>
array
0 => boolean false
1 => boolean true
Alors que j'aurais préféré le résultat suivant :
array
'cache modules' => boolean true
Pas vraiment ce à quoi on pourrait s'attendre
Alors oui, vu le résultat autant utiliser la fonction array_merge. Pourtant, j'ai vraiment besoin de la récursion, sinon comment combiner les tableaux suivants :
<?php
$ar1 = array
(
'use cache' => false,
'modules' => array
(
'WdCore' => 'wdcore.php'
)
);
$ar2 = array
(
'use cache' => true,
'modules' => array
(
'WdPatron' => 'wdpatron.php'
)
);
?>
Pour obtenir le résultat suivant :
array
'cache modules' => boolean true
'modules' =>
array
'WdCore' => string 'wdcore.php' (length=10)
'WdPatron' => string 'wdpatron.php' (length=12)
Ce que dit la documentation
Si les tableaux passés en arguments ont les mêmes clés (chaînes de caractères), les valeurs sont alors rassemblées dans un tableau, de manière récursive, de façon à ce que, si l'une de ces valeurs est un tableau elle-même, la fonction la rassemblera avec les valeurs de l'entrée courante.
J'ai mis en évidence « si l'une de ces valeurs est un tableau elle-même », parce que c'est là, pour moi, que le bât blesse. En effet, cache modules n'est pas un tableau. Pourquoi se trouve-t-il convertit de force ?
array_merge_recursive corrigée
La fonction wd_array_merge_recursive est ce que j'attendais en terme de combinaison de tableaux. La combinaison de deux clés identiques se fait en deux temps :
- Si, et seulement si, le type de la valeur du second tableau est un tableau associatif, alors la valeur du premier tableau est transformée en tableau et les deux tableaux sont combinés.
ensuite, tout dépend de la clé :
- Si la clé est numérique alors la valeur est ajoutée au tableau
- dans le cas contraire, la valeur de la clé est remplacée.
<?php
function wd_array_merge_recursive(array $array1, array $array2=array())
{
$arrays = func_get_args();
$merge = array_shift($arrays);
foreach ($arrays as $array)
{
foreach ($array as $key => $val)
{
#
# if the value is an array and the key already exists
# we have to make a recursion
#
if (is_array($val) && array_key_exists($key, $merge))
{
$val = wd_array_merge_recursive((array) $merge[$key], $val);
}
#
# if the key is numeric, the value is pushed. Otherwise, it replaces
# the value of the _merge_ array.
#
if (is_numeric($key))
{
$merge[] = $val;
}
else
{
$merge[$key] = $val;
}
}
}
return $merge;
}
?>
Trois méthodes de combinaison
Voyons ce que cela donne si l'on combine les tableaux suivants avec les fonctions array_merge, array_merge_recursive et wd_array_merge_recursive.
<?php
$ar1 = array
(
'color' => array
(
'favorite' => 'red'
),
5,
'use cache' => false,
'modules' => array
(
'WdCore' => 'wdcore.php'
),
'var1' => array(1, 2),
'var2' => 1
);
$ar2 = array
(
10,
'color' => array
(
'favorite' => 'green',
'blue'
),
'use cache' => true,
'modules' => array
(
'WdPatron' => 'wdpatron.php'
),
'var1' => 1,
'var2' => array(2, 3)
);
?>
Résultat pour array_merge
array
'color' =>
array
'favorite' => string 'green' (length=5)
0 => string 'blue' (length=4)
0 => int 5
'use cache' => boolean true
'modules' =>
array
'WdPatron' => string 'wdpatron.php' (length=12)
'var1' => int 1
'var2' =>
array
0 => int 2
1 => int 3
1 => int 10
Résultat pour array_merge_recursive
array
'color' =>
array
'favorite' =>
array
0 => string 'red' (length=3)
1 => string 'green' (length=5)
0 => string 'blue' (length=4)
0 => int 5
'use cache' =>
array
0 => boolean false
1 => boolean true
'modules' =>
array
'WdCore' => string 'wdcore.php' (length=10)
'WdPatron' => string 'wdpatron.php' (length=12)
'var1' =>
array
0 => int 1
1 => int 2
2 => int 1
'var2' =>
array
0 => int 1
1 => int 2
2 => int 3
1 => int 10
Résultat pour wd_array_merge_recursive
array
'color' =>
array
'favorite' => string 'green' (length=5)
0 => string 'blue' (length=4)
0 => int 5
'use cache' => boolean true
'modules' =>
array
'WdCore' => string 'wdcore.php' (length=10)
'WdPatron' => string 'wdpatron.php' (length=12)
'var1' => int 1
'var2' =>
array
0 => int 1
1 => int 2
2 => int 3
1 => int 10
Par rapport à array_merge_recursive, on peut constater que les valeurs de modules ont étaient combinées avec merveille et que var2 comporte bien une nouvelle entrée. Par contre il y a des différences :
favoritea été changé deredàgreenuse cachea été changé defalseàtruevar1est maintenant un entier puisque c'est comme cela qu'il est défini dans le second tableau
Conlusion
Si le comportement de array_merge_recursive ne vous a jamais gêné, c'est tant mieux. En tout cas, vous aurez maintenant l'embarras du choix quand à la méthode à utiliser pour combiner vos tableaux associatifs.