为什么 array_map() 以 null 作为回调创建一个 "array of arrays"?

Why does array_map() with null as callback create an "array of arrays"?

今天了解到PHP中array_map()的一个特例,在文档中作为旁注提到:

Example #4 Creating an array of arrays

<?php
$a = array(1, 2, 3, 4, 5);
$b = array("one", "two", "three", "four", "five");
$c = array("uno", "dos", "tres", "cuatro", "cinco");

$d = array_map(null, $a, $b, $c);
print_r($d);
?>

The above example will output:

Array
(
    [0] => Array
        (
            [0] => 1
            [1] => one
            [2] => uno
        )

    [1] => Array
        (
            [0] => 2
            [1] => two
            [2] => dos
        )

    [2] => Array
        (
            [0] => 3
            [1] => three
            [2] => tres
        )

    [3] => Array
        (
            [0] => 4
            [1] => four
            [2] => cuatro
        )

    [4] => Array
        (
            [0] => 5
            [1] => five
            [2] => cinco
        )

)

If the array argument contains string keys then the returned array will contain string keys if and only if exactly one array is passed. If more than one argument is passed then the returned array always has integer keys.

(try it out)

但仅此而已。没有更多的解释。我明白,这与

$d = array_map(function() { return func_get_args(); }, $a, $b, $c);

但为什么会有人想要或期望这是默认行为?它之所以这样工作,是否有技术原因,比如实施的副作用?或者这只是一个随机的 "let's make this function do one more thing" 决定(看着你,array_multisort())?

这似乎是 _array_map_ 中的一个特例,但它仅记录在该示例中。 NULL 通常不允许作为回调(如果您尝试将它与 call_user_func() 一起使用,它会报告错误),但在 _array_map()_ 中是允许的。它将 NULL 视为意味着它应该简单地创建一个参数数组。

这很有用,因为 array 作为回调也无效,因为它是语言构造,而不是函数。所以你不能写:

$d = array_map('array', $a, $b, $c);

array_map(null, ...[arrays]) 执行“转置”。有些人将此 re-orientation 称为“对角线翻转”,但它在功能上转化为将数据列转换为数据行。

即使在 PHP 的最新版本(本 post 时的 8.1)中,这种不直观的本机技术仍然只适用于转置 numerically-keyed 数组 numerically-keyed 数组 SO LONG AS 不止一行(子数组)。

为清楚起见,array_map(null, ...[$a, $b, $c]) 中展开运算符的实现与 array_map(null, $a, $b, $c) 基本相同。

使用这种技术为图形或表格表示形式准备数据的开发人员喜欢简洁(尽管隐晦)的语法——它比拼写两个嵌套的 foreach 循环更性感。

这些开发人员可能会惊讶地发现,当没有多行数据要转置时,原始二维数组会缩减为一维数组。在这种情况下,null 参数版本与 func_get_args() 版本不同。

代码:(Demo)

$array = [
    [1 => 'one', 2 => 'two', 3 => 'three']
];
var_export(array_map(fn() => func_get_args(), ...$array));
echo "\n---\n";
var_export(array_map(null, ...$array));

输出:

array (
  1 => 
  array (
    0 => 'one',
  ),
  2 => 
  array (
    0 => 'two',
  ),
  3 => 
  array (
    0 => 'three',
  ),
)
---
array (
  1 => 'one',
  2 => 'two',
  3 => 'three',
)

总而言之,我不能代表语言开发人员说明为什么这种 array_map() 技术是这样设计的,但我想借此机会警告开发人员不要被它的魅力所吸引。它会破坏数字键与其值之间的关联关系,并且可能会意外地展平您的输出数组。换句话说,请确保您的数据适用于该技术,因为该技术并不适用于所有数据。