为什么 array_merge_recursive 不是递归的?
Why is array_merge_recursive not recursive?
我最近在我的应用程序中发现了一个由 array_merge_recursive
的意外行为引起的错误。让我们来看看这个简单的例子:
$array1 = [
1 => [
1 => 100,
2 => 200,
],
2 => [
3 => 1000,
],
3 => [
1 => 500
]
];
$array2 = [
3 => [
1 => 500
]
];
array_merge_recursive($array1, $array2);
//returns: array:4 [ 0 => //...
我希望得到一个包含 3 个元素的数组:键 1、2 和 3。但是,函数 returns 是一个包含键 0、1、2 和 3 的数组。所以有 4 个元素,而我预期只有 3。当我用它们的字母等效项 (a、b、c) 替换数字时,它 returns 一个只有 3 个元素的数组:a、b 和 c。
$array1 = [
'a' => [
1 => 100,
2 => 200,
],
'b' => [
3 => 1000,
],
'c' => [
1 => 500
]
];
$array2 = [
'c' => [
1 => 500
]
];
array_merge_recursive($array1, $array2);
//returns: array:3 [ 'a' => //...
这是(至少对我而言)意外的行为,但至少它被记录在案:
http://php.net/manual/en/function.array-merge-recursive.php
If the input arrays have the same string keys, then the values for
these keys are merged together into an array, and this is done
recursively, so that if one of the values is an array itself, the
function will merge it with a corresponding entry in another array
too. If, however, the arrays have the same numeric key, the later
value will not overwrite the original value, but will be appended.
文档对 'appended' 的含义不是很清楚。事实证明,$array1
中带有数字键的元素将被视为索引元素,因此它们将丢失当前键:返回的数组以 0 开头。这将在同时使用数字和字符串时导致奇怪的结果数组中的键,但如果您使用这样的错误做法,我们不要责怪 PHP。在我的例子中,问题是通过使用 array_replace_recursive
来解决的,这达到了预期的效果。 ('replace' 在该函数中表示如果存在则替换,否则追加;命名函数很难!)
问题一:递归与否?
但这不是这个问题的结束。我以为 array_*_resursive
会是一个递归函数:
Recursion is a kind of function call in which a function calls itself.
Such functions are also called recursive functions. Structural
recursion is a method of problem solving where the solution to a
problem depends on solutions to smaller instances of the same problem.
事实证明并非如此。虽然 $array1
和 $array2
是关联数组,但上例中的 $array1['c']
和 $array2['c']
都是具有一个元素的索引数组:[1 => 500]
。让我们合并它们:
array_merge_recursive($array1['c'], $array2['c']);
//output: array:2 [0 => 500, 1 => 500]
这是预期的输出,因为两个数组都有一个数字键 (1
),所以第二个将附加到第一个。新数组以键 0 开始。但让我们回到第一个示例:
array_merge_recursive($array1, $array2);
// output:
// array:3 [
// "a" => array:2 [
// 1 => 100
// 2 => 200
// ]
// "b" => array:1 [
// 3 => 1000
// ]
// "c" => array:2 [
// 1 => 500 //<-- why not 0 => 500?
// 2 => 500
// ]
//]
$array2['c'][1]
附加到 $array1['c']
但它具有键 1 和 2。在前面的示例中不是 0 和 1。在处理整数键时,主数组及其子数组的处理方式不同。
问题 2:字符串或整数键有很大区别。
在写这个问题的时候,我发现了一些别的东西。在子数组中用字符串键替换数字键时会变得更加混乱:
$array1 = [
'c' => [
'a' => 500
]
];
$array2 = [
'c' => [
'a' => 500
]
];
array_merge_recursive($array1, $array2);
// output:
// array:1 [
// "c" => array:1 [
// "a" => array:2 [
// 0 => 500
// 1 => 500
// ]
// ]
//]
因此使用字符串键会将 (int) 500
转换为 array(500)
,而使用整数键则不会。
有人可以解释这种行为吗?
您应该阅读您提供的 link 声明(强调我的):
If the input arrays have the same string keys, then the values for these keys are merged together into an array, and this is done recursively, so that if one of the values is an array itself, the function will merge it with a corresponding entry in another array too. If, however, the arrays have the same numeric key, the later value will not overwrite the original value, but will be appended.
如果我们退后一步,观察 array_merge*()
函数如何只处理一个数组,那么我们就能瞥见它如何以不同方式处理关联数组和索引数组:
$array1 = [
'k' => [
1 => 100,
2 => 200,
],
2 => [
3 => 1000,
],
'f' => 'gf',
3 => [
1 => 500
],
'99' => 'hi',
5 => 'g'
];
var_dump( array_merge_recursive( $array1 ) );
输出:
array(6) {
["k"]=>
array(2) {
[1]=>
int(100)
[2]=>
int(200)
}
[0]=>
array(1) {
[3]=>
int(1000)
}
["f"]=>
string(2) "gf"
[1]=>
array(1) {
[1]=>
int(500)
}
[2]=>
string(2) "hi"
[3]=>
string(1) "g"
}
如您所见,它采用了所有数字键并忽略了它们的实际值,并按照遇到它们的顺序将它们返回给您。我想该函数是故意这样做的,以保持底层 C 代码的完整性(或效率)。
回到你的两个数组示例,它采用 $array1
的值,对它们进行排序,然后 然后 附加 $array2
.
这种行为是否正常是一个完全不同的讨论...
我最近在我的应用程序中发现了一个由 array_merge_recursive
的意外行为引起的错误。让我们来看看这个简单的例子:
$array1 = [
1 => [
1 => 100,
2 => 200,
],
2 => [
3 => 1000,
],
3 => [
1 => 500
]
];
$array2 = [
3 => [
1 => 500
]
];
array_merge_recursive($array1, $array2);
//returns: array:4 [ 0 => //...
我希望得到一个包含 3 个元素的数组:键 1、2 和 3。但是,函数 returns 是一个包含键 0、1、2 和 3 的数组。所以有 4 个元素,而我预期只有 3。当我用它们的字母等效项 (a、b、c) 替换数字时,它 returns 一个只有 3 个元素的数组:a、b 和 c。
$array1 = [
'a' => [
1 => 100,
2 => 200,
],
'b' => [
3 => 1000,
],
'c' => [
1 => 500
]
];
$array2 = [
'c' => [
1 => 500
]
];
array_merge_recursive($array1, $array2);
//returns: array:3 [ 'a' => //...
这是(至少对我而言)意外的行为,但至少它被记录在案:
http://php.net/manual/en/function.array-merge-recursive.php
If the input arrays have the same string keys, then the values for these keys are merged together into an array, and this is done recursively, so that if one of the values is an array itself, the function will merge it with a corresponding entry in another array too. If, however, the arrays have the same numeric key, the later value will not overwrite the original value, but will be appended.
文档对 'appended' 的含义不是很清楚。事实证明,$array1
中带有数字键的元素将被视为索引元素,因此它们将丢失当前键:返回的数组以 0 开头。这将在同时使用数字和字符串时导致奇怪的结果数组中的键,但如果您使用这样的错误做法,我们不要责怪 PHP。在我的例子中,问题是通过使用 array_replace_recursive
来解决的,这达到了预期的效果。 ('replace' 在该函数中表示如果存在则替换,否则追加;命名函数很难!)
问题一:递归与否?
但这不是这个问题的结束。我以为 array_*_resursive
会是一个递归函数:
Recursion is a kind of function call in which a function calls itself. Such functions are also called recursive functions. Structural recursion is a method of problem solving where the solution to a problem depends on solutions to smaller instances of the same problem.
事实证明并非如此。虽然 $array1
和 $array2
是关联数组,但上例中的 $array1['c']
和 $array2['c']
都是具有一个元素的索引数组:[1 => 500]
。让我们合并它们:
array_merge_recursive($array1['c'], $array2['c']);
//output: array:2 [0 => 500, 1 => 500]
这是预期的输出,因为两个数组都有一个数字键 (1
),所以第二个将附加到第一个。新数组以键 0 开始。但让我们回到第一个示例:
array_merge_recursive($array1, $array2);
// output:
// array:3 [
// "a" => array:2 [
// 1 => 100
// 2 => 200
// ]
// "b" => array:1 [
// 3 => 1000
// ]
// "c" => array:2 [
// 1 => 500 //<-- why not 0 => 500?
// 2 => 500
// ]
//]
$array2['c'][1]
附加到 $array1['c']
但它具有键 1 和 2。在前面的示例中不是 0 和 1。在处理整数键时,主数组及其子数组的处理方式不同。
问题 2:字符串或整数键有很大区别。
在写这个问题的时候,我发现了一些别的东西。在子数组中用字符串键替换数字键时会变得更加混乱:
$array1 = [
'c' => [
'a' => 500
]
];
$array2 = [
'c' => [
'a' => 500
]
];
array_merge_recursive($array1, $array2);
// output:
// array:1 [
// "c" => array:1 [
// "a" => array:2 [
// 0 => 500
// 1 => 500
// ]
// ]
//]
因此使用字符串键会将 (int) 500
转换为 array(500)
,而使用整数键则不会。
有人可以解释这种行为吗?
您应该阅读您提供的 link 声明(强调我的):
If the input arrays have the same string keys, then the values for these keys are merged together into an array, and this is done recursively, so that if one of the values is an array itself, the function will merge it with a corresponding entry in another array too. If, however, the arrays have the same numeric key, the later value will not overwrite the original value, but will be appended.
如果我们退后一步,观察 array_merge*()
函数如何只处理一个数组,那么我们就能瞥见它如何以不同方式处理关联数组和索引数组:
$array1 = [
'k' => [
1 => 100,
2 => 200,
],
2 => [
3 => 1000,
],
'f' => 'gf',
3 => [
1 => 500
],
'99' => 'hi',
5 => 'g'
];
var_dump( array_merge_recursive( $array1 ) );
输出:
array(6) {
["k"]=>
array(2) {
[1]=>
int(100)
[2]=>
int(200)
}
[0]=>
array(1) {
[3]=>
int(1000)
}
["f"]=>
string(2) "gf"
[1]=>
array(1) {
[1]=>
int(500)
}
[2]=>
string(2) "hi"
[3]=>
string(1) "g"
}
如您所见,它采用了所有数字键并忽略了它们的实际值,并按照遇到它们的顺序将它们返回给您。我想该函数是故意这样做的,以保持底层 C 代码的完整性(或效率)。
回到你的两个数组示例,它采用 $array1
的值,对它们进行排序,然后 然后 附加 $array2
.
这种行为是否正常是一个完全不同的讨论...