一、array_pad()是干什么的
PHP里给数组补位,array_pad()是直接能用的内置函数。它的作用是把一个数组“撑”到指定长度,不够的部分用指定的值填上。
函数原型:
array array_pad(array $array, int $size, mixed $value);
三个参数都是必填:
-
$array:原始数组 -
$size:填充后数组的总长度 -
$value:用来补位的值
返回一个填充后的新数组。原数组不变——这点很重要,它不是引用修改,而是返回副本。
有个细节说明书里写得很清楚但容易被跳过:如果size小于原数组长度,array_pad()不会删除任何元素,直接返回原数组。它只负责“补”,不负责“削”。
二、size的正负决定了往哪边补
这是array_pad()最容易搞混的地方。size不只是“目标长度”,它的符号还决定了填充方向。
size为正数,在数组末尾追加:
$input_array = array(1, 11, 10, 12);
$result = array_pad($input_array, 6, 100);
print_r($result);
输出:
Array
(
[0] => 1
[1] => 11
[2] => 10
[3] => 12
[4] => 100
[5] => 100
)
原数组4个元素,size是6,差2个,所以在后面补两个100。
size为负数,在数组开头插入:
$computer = array("compiler", "computing");
print_r(array_pad($computer, -5, "database"));
输出:
Array
(
[0] => database
[1] => database
[2] => database
[3] => compiler
[4] => computing
)
size是-5,意思是要凑到5个元素,方向是从前面补。差了3个,就在开头塞三个database,原有两个元素往后挪。
正数往后、负数往前,绝对值才是目标长度。这个设计一开始我觉得别扭,用几次之后反而觉得省事——方向直接写在参数里,不用额外传一个标志位。
三、size小于原数组长度时会发生什么
假设数组已经有5个元素,你传size=3:
$arr = array("code1", "code2", "code3", "code4", "code5");
$result = array_pad($arr, 3, "empty");
print_r($result);
结果还是那5个元素,一个不少。array_pad()直接返回原数组的副本,不做任何截断。
这个行为和array_slice()正好相反。array_slice()是拿来截取的,array_pad()只管补。如果你需要“不足补、超出截”,得自己写判断:
function fitArray($arr, $size, $value) {
if (count($arr) >= abs($size)) {
return array_slice($arr, 0, abs($size));
}
return array_pad($arr, $size, $value);
}
我在项目里遇到过这种需求:固定展示5个卡片位,数据不够就填占位符,数据多了就截掉。当时第一反应是用array_pad(),结果发现多出来的数据没被去掉,页面布局直接撑破了。后来才补上array_slice()的判断。这个坑不算深,但第一次碰容易想当然。
四、关联数组的键名处理
array_pad()对关联数组的处理有个明确规则:原键名保留,新补的元素用数字键,从0开始往后排。
$input1 = array("a" => "apple", "b" => "ball", "c" => "cat");
print_r(array_pad($input1, 6, "code"));
输出:
Array
(
[a] => apple
[b] => ball
[c] => cat
[0] => code
[1] => code
[2] => code
)
原来的字符串键a、b、c都还在,新补的三个元素拿的是0、1、2。注意,即使原数组里已经有数字键,新补的键也不会和它们冲突——PHP会从当前较大的整数键之后继续排。
再看一个混合键的例子:
$a = array('size' => 'exact', 'number' => 100, 'color' => 'green');
print_r(array_pad($a, 5, 'code'));
输出:
Array
(
[size] => exact
[number] => 100
[color] => green
[0] => code
[1] => code
)
字符串键原样保留,补位的元素从0开始编号。
这里有个实际影响:如果补位后你要用数字索引遍历,得注意原数组里可能本来就有数字键,新补的键不一定从0开始。比如原数组是array(5=>"x"),补位后的新键会是6、7、8,而不是0、1、2。
$arr = array(5 => "code5");
print_r(array_pad($arr, 4, "new"));
输出:
Array
(
[5] => code5
[6] => new
[7] => new
[8] => new
)
PHP取当前较大整数键加一作为新键的起点。这个规则和数组追加元素的逻辑一致。
五、和array_fill()、array_merge()的区别
array_pad()不是唯一能补数组的函数,但它的定位和其他几个不一样。
array_fill()是凭空造一个全是某值的数组,不依赖已有数组:
array_fill(0, 3, "code"); // array("code", "code", "code")
它解决的是“从无到有”,array_pad()解决的是“从有到够”。
array_merge()是合并两个数组,长度是两者之和,不能指定目标长度:
array_merge(array("a"), array("b", "c")); // array("a", "b", "c")
如果你要把一个数组补到固定长度,用array_merge()还得先算出差多少,再调array_fill(),两步。array_pad()一步到位。
array_slice()是截取,和array_pad()方向相反。两者搭配可以做出“定长数组”的效果。
选哪个取决于你要的是“补”“造”还是“截”。array_pad()的独特之处在于它同时接受目标长度和方向,语义集中在一个调用里。
六、本节课程知识要点
-
array_pad()把数组填充到指定长度,返回新数组,原数组不变。
-
size的符号决定方向:正数在末尾补,负数在开头补,绝对值是目标长度。
-
size小于原数组长度时不截断,直接返回原数组副本。需要截断要配合array_slice()。
-
关联数组的字符串键保留,新补元素使用数字键,从当前较大整数键之后开始。
-
补位的值可以是任意类型,包括数组、对象、null,PHP不做类型限制。
-
它只负责补,不负责削,这是和array_slice()的核心分工差异。
-
和array_fill()、array_merge()的定位不同:一个从无造,一个合并,array_pad()是从有补到指定长度。
七、实际用起来的一些观察
补位值用引用类型要注意。如果$value是个对象,补出来的多个元素指向同一个对象实例,改一个全变。要独立对象得用循环自己new:
$arr = array();
for ($i = 0; $i < 3; $i++) {
$arr[] = new stdClass();
}
用array_pad()补对象,拿到的是一串指向同一实例的引用。这个坑在补配置对象、补模型实例的时候容易踩。
补null是常见用法。做表格渲染时,经常需要把数据行补到固定列数,不够的填null,前端判断null显示空单元格。这种场景array_pad()很顺手。
$row = array("code1", "code2");
$padded = array_pad($row, 5, null);
// array("code1", "code2", null, null, null)
负数size在队列场景有用。比如日志按时间倒序排列,新的在前面,你想在开头补几条占位记录,负size正好。
别用它做数据校验。array_pad()不会告诉你原数组是多长、补了几个,它只返回结果。如果业务逻辑需要知道“补了多少”,自己先算abs($size)-count($array),别从结果反推。
性能上不用纠结。补位是浅拷贝,元素多的时候内存会上去,但日常几百几千个元素的场景,和手写循环比没明显差别。真到了大数据量,瓶颈通常不在这一步。
array_pad()的参数少,但size的符号语义和“不截断”这两个点,决定了它的适用边界。记住它是“补”不是“截”,是“返回新数组”不是“改原数组”,是“正尾负头”。关联数组补位后键名会混着字符串键和数字键,遍历时用foreach比用for稳妥。需要定长数组时,把它和array_slice()配合起来用,比单用一个函数更贴近实际需求。