在 PHP 中,array_fill() 是一个非常方便的函数,用于用指定的值填充数组。它通常用于初始化数组,特别是在我们需要快速生成一个默认值数组时。然而,很多开发者在使用 array_fill() 创建二维数组时,容易陷入一些常见的误区,导致程序出现意想不到的行为。本文将探讨这些常见错误以及如何正确地避免它们。
在深入问题之前,先简单回顾一下 array_fill() 的基本用法:
$filledArray = array_fill(0, 5, 'default');
// 结果: ['default', 'default', 'default', 'default', 'default']
这个函数接受三个参数:
起始索引(从哪个索引开始填充)
数组长度(填充几个元素)
填充值
当我们试图使用 array_fill() 来创建一个二维数组,比如 5 行,每行 3 个默认值 'default',许多开发者会写出如下代码:
$matrix = array_fill(0, 5, array_fill(0, 3, 'default'));
乍一看,这样的写法似乎是合理的。输出结果也如预期:
[
['default', 'default', 'default'],
['default', 'default', 'default'],
['default', 'default', 'default'],
['default', 'default', 'default'],
['default', 'default', 'default']
]
但问题在于:这些子数组其实是同一个数组的引用!
也就是说,如果我们修改其中一个子数组的值:
$matrix[0][0] = 'changed';
会导致所有行的第一个值都变成 'changed':
[
['changed', 'default', 'default'],
['changed', 'default', 'default'],
['changed', 'default', 'default'],
['changed', 'default', 'default'],
['changed', 'default', 'default']
]
这是由于 array_fill() 在第三个参数是数组时,填充的是同一个数组的引用,而不是每次创建一个新的数组实例。
为了解决这个问题,我们需要确保每个子数组都是独立的实例。最稳妥的做法是使用循环:
$matrix = [];
for ($i = 0; $i < 5; $i++) {
$matrix[$i] = array_fill(0, 3, 'default');
}
这样就能保证每一行的数组都是新的副本,相互之间不会相互影响。
如果你封装了一个创建二维数组的函数,也要注意不要在函数外部创建子数组然后复用。例如:
错误示范:
function createMatrix($rows, $cols, $defaultValue) {
$rowTemplate = array_fill(0, $cols, $defaultValue);
return array_fill(0, $rows, $rowTemplate);
}
这个问题和上面描述的一样,所有行都引用了同一个 $rowTemplate。修改一行,会影响所有行。
正确写法:
function createMatrix($rows, $cols, $defaultValue) {
$matrix = [];
for ($i = 0; $i < $rows; $i++) {
$matrix[] = array_fill(0, $cols, $defaultValue);
}
return $matrix;
}
假设你在构建一个在线填空题生成工具(比如 https://m66.net/tools/quiz-generator),需要创建一个空白题板,其中每格默认值为 null:
$questionBoard = [];
for ($i = 0; $i < 10; $i++) {
$questionBoard[] = array_fill(0, 5, null);
}
这样的做法可以避免将整个题板意外共享内存,从而在用户交互或后续逻辑中引发 Bug。
array_fill() 是一个高效的工具,但当涉及到嵌套数组(二维或多维)时,我们必须警惕共享引用的问题。通过使用循环并确保每个子数组是一个新的实例,我们就能构建更加健壮和可预测的数据结构。
理解 PHP 中的值与引用机制,不仅有助于避免这个问题,也能提升你在大型项目中处理复杂数组结构的能力。