PHP数组追加元素只懂array_push? 你太天真了!

最近在重构一个老项目,遇到了一个看似简单却暗藏玄机的问题:如何优雅地往PHP数组里追加元素。这让我想起了当年刚学PHP时,只会用array_push的日子,现在回头看简直太naive了。今天就来聊聊PHP数组追加的各种姿势,顺便分享几个实战中踩过的坑。

先来看最基础的array_push用法:

$fruits = ['apple', 'banana'];

array_push($fruits, 'orange');

// 现在$fruits是['apple', 'banana', 'orange']

看起来很简单对?但这里有个性能陷阱。array_push在处理单个元素时,其实比直接使用[]语法要慢。因为array_push是个函数调用,而[]是语言结构。当你在循环里大量使用时,这个差异就会很明显。

说到[]语法,这是我最喜欢的追加方式:

$fruits[] = 'pear';

// 简单粗暴有效

但有时候你会遇到这样的情况:

$fruits = null;

$fruits[] = 'apple'; // 报错:Warning: Cannot use a scalar value as an array

这时候就需要先初始化数组:

$fruits = [];

$fruits[] = 'apple'; // 这下舒服了

在实战中,我经常需要合并数组。array_merge是个不错的选择:

$arr1 = ['a', 'b'];

$arr2 = ['c', 'd'];

$result = array_merge($arr1, $arr2);

// $result是['a', 'b', 'c', 'd']

但要注意,array_merge会重新索引数字键。如果你想保留数字键,可以用+运算符:

$arr1 = [0 => 'a', 1 => 'b'];

$result = $arr1 + $arr2;

// $result是[0 => 'a', 1 => 'b']

因为+运算符遇到相同键名时会保留第一个数组的值。这个特性在处理配置合并时特别有用。

说到配置合并,不得不提array_replace。它和array_merge的区别在于,array_replace会保留键名,包括数字键:

$defaults = ['color' => 'red', 'size' => 'M'];

$userPref = ['color' => 'blue'];

$result = array_replace($defaults, $userPref);

// $result是['color' => 'blue', 'size' => 'M']

在处理多维数组时,你可能需要array_merge_recursive:

$arr1 = ['fruits' => ['apple', 'banana']];

$arr2 = ['fruits' => ['orange']];

$result = array_merge_recursive($arr1, $arr2);

// $result是['fruits' => ['apple', 'banana', 'orange']]

但要注意,如果键名相同但值不是数组,它会把这些值合并到一个数组里:

$arr1 = ['count' => 1];

// $result是['count' => [1, 2]]

这有时候不是你想要的。这时候可以考虑自己写递归合并函数。

说到自定义函数,在处理大量数据追加时,性能很重要。我曾经在一个项目中需要处理百万级数据的追加,发现用[]比array_push快30%左右。测试代码如下:

$start = microtime(true);

$arr = [];

for ($i = 0; $i < 1000000; $i++) {

$arr[] = $i;

}

$end = microtime(true);

echo '[]用时:'.($end - $start).'秒';

array_push($arr, $i);

}

echo 'array_push用时:'.($end - $start).'秒';

在处理关联数组时,有个小技巧可以快速追加多个元素:

$user = ['name' => 'John'];

$user += ['age' => 30, 'gender' => 'male'];

// $user现在是['name' => 'John', 'age' => 30, 'gender' => 'male']

这比多次使用[]或者array_merge要简洁得多。

有时候我们需要在数组开头追加元素,这时候array_unshift就派上用场了:

$queue = ['b', 'c'];

array_unshift($queue, 'a');

// $queue现在是['a', 'b', 'c']

但要注意,array_unshift会重新索引数字键,这在处理某些数据结构时可能会带来问题。

在PHP7.4之后,我们可以使用展开运算符(...)来追加数组:

$arr1 = [1, 2];

$arr2 = [3, 4];

$result = [...$arr1, ...$arr2];

// $result是[1, 2, 3, 4]

这个语法糖在处理参数传递时特别有用。

说到参数传递,在处理可变参数函数时,func_get_args()返回的参数数组经常需要追加到其他数组中。这时候可以这样:

function foo(...$args) {

$defaults = ['a', 'b'];

return [...$defaults, ...$args];

}

foo('c', 'd'); // 返回['a', 'b', 'c', 'd']

在处理数据库结果时,我经常需要把查询结果追加到数组中。PDO的fetchAll可以直接返回数组,但有时候我们需要处理每一行:

$results = [];

while ($row = $stmt->fetch()) {

$results[] = $row;

}

这里有个性能优化点:如果知道结果集大小,可以先预分配数组大小:

$results = array_fill(0, $estimatedCount, null);

foreach ($results as &$row) {

$row = $stmt->fetch();

}

这样可以避免PHP频繁调整数组大小带来的性能开销。

在处理JSON API时,经常需要构建嵌套数组。这时候要注意引用的问题:

$data = ['items' => []];

$items = &$data['items'];

$items[] = ['id' => 1];

// $data现在是['items' => [['id' => 1]]]

使用引用可以避免多次写$data['items'],但要小心不要在不需要的地方意外创建引用。

最后分享一个真实案例:有一次我需要处理一个超大CSV文件,每行都要追加到数组中。直接使用[]导致内存爆炸,因为PHP数组的内存使用效率不高。解决方案是使用SplFixedArray:

$data = new SplFixedArray($lineCount);

foreach ($data as $i => &$row) {

$row = fgetcsv($handle);

}

SplFixedArray比普通数组更节省内存,特别是处理大量数值数据时。

总结一下PHP数组追加的各种姿势:

简单追加:$arr[] = $value

批量追加:array_merge, +, ...

开头追加:array_unshift

性能优化:预分配大小,SplFixedArray

特殊需求:array_replace, array_merge_recursive

记住,没有最好的方法,只有最适合当前场景的方法。选择时要考虑:是否需要保留键名、性能要求、代码可读性等因素。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值