一、array_replace()的语义
这个函数做的事可以用一句话概括:以第一个数组为底,用后面的数组按"键"去覆盖它。
注意关键词是"按键"。它不关心值的类型,也不做递归合并,只看键名是否相同。键名相同就替换,键名不存在就追加。理解这一点,后面所有行为都能推出来。
和array_merge()容易混。array_merge()对数字键是重新编号追加,对字符串键是后者覆盖前者;array_replace()对数字键和字符串键一视同仁,都是同键覆盖、无键追加。这是两者最本质的区别。
二、函数原型与参数
array_replace(array $array1, array ...$replacements): array
| 参数 | 说明 | 是否必需 |
|---|---|---|
| array1 | 被替换的基准数组 | 必需 |
| replacements | 一个或多个替换数组 | 可选 |
返回值:替换后的新数组。原数组不受影响。如果传入的参数不是数组,返回null。
替换数组可以有多个,后面的数组会覆盖前面数组的同名键,顺序不能颠倒。
三、字符串键的覆盖
字符串键是最直观的场景:
<?php
$config = array("j" => "java", "p" => "php");
$override = array("j" => "javatpoint");
print_r(array_replace($config, $override));
输出:
Array
(
[j] => javatpoint
[p] => php
)
键j被替换,键p因为第二个数组里没有,保留原值。这就是配置覆盖的典型形态。
再看一个多数组叠加的例子:
<?php
$a1 = array("a" => "Sonoo", "java");
$a2 = array("a" => "javatpoint", "b" => "PHP");
print_r(array_replace($a1, $a2));
输出:
Array
(
[a] => javatpoint
[0] => java
[b] => PHP
)
字符串键a被覆盖,数字键0保留,新键b追加。
四、数字键的覆盖,这是重点
很多教程对数字键一笔带过,实际项目里这里最容易出问题。看例子:
<?php
$city1 = array("a" => "Patna", "b" => "chennai");
$city2 = array("a" => "Pataliputra", "Noida");
print_r(array_replace($city1, $city2));
输出:
Array
(
[a] => Pataliputra
[b] => chennai
[0] => Noida
)
$city2里的"Noida"没有指定键,PHP给它分配了数字键0。$city1里没有0号键,所以直接追加。如果$city1里本来就有0号键,就会被覆盖。
更典型的是下面这个:
<?php
$player1 = array("sachin", "sehwag", "kapil", "rahul");
$player2 = array(0 => "rohit", 4 => "klrahul");
$player3 = array(0 => "arjun");
$res = array_replace($player1, $player2, $player3);
print_r($res);
输出:
Array
(
[0] => arjun
[1] => sehwag
[2] => kapil
[3] => rahul
[4] => klrahul
)
逐个键看:
-
键0:先被
$player2的rohit覆盖,再被$player3的arjun覆盖,最终是arjun。 -
键1、2、3:后续数组没有这些键,保留
$player1的原值。 -
键4:
$player2新增,追加为klrahul。
这里没有发生任何"重新编号"。数字键0到4的对应关系是稳定的,这正是array_replace()和array_merge()在数字键上的分水岭。用array_replace()处理带固定下标的数组时,下标不会被打乱。
五、与array_merge、array_replace_recursive的取舍
| 函数 | 数字键行为 | 字符串键行为 | 嵌套数组 |
|---|---|---|---|
| array_replace() | 同键覆盖,无键追加 | 同键覆盖 | 不递归,整体替换 |
| array_merge() | 重新编号追加 | 同键覆盖 | 不递归 |
| array_replace_recursive() | 同键覆盖 | 同键覆盖 | 递归逐层替换 |
+运算符 |
同键保留左侧 | 同键保留左侧 | 不递归 |
选择原则:
-
需要保留数字键的下标语义,用array_replace()。
-
合并列表类数据、下标无意义,用array_merge()。
-
多层配置需要逐层覆盖,用array_replace_recursive()。
-
只想要"补齐缺失键"、已有键不覆盖,用
+运算符。
个人经验:做过一个多环境配置系统,默认配置和用户配置都是嵌套数组。一开始用array_replace()合并,结果用户只改了数据库密码,整个database子数组把默认的host、port全顶掉了,连接直接失败。换成array_replace_recursive()后,只覆盖用户显式指定的键,其余保留。嵌套配置用array_replace()是常见的误用,这是踩过坑才记住的。
另一个经验:处理分页数据时,接口返回的数组带固定数字下标,前端按位置取值。这种场景如果用array_merge()合并默认值和返回值,下标会被重排,前端全乱。array_replace()在这里才合适。
六、项目实例
实例一:代码号学习编程·多环境配置覆盖
<?php
$default = [
'host' => 'localhost',
'port' => 3306,
'user' => 'root',
];
$userConfig = [
'host' => '192.168.1.10',
'user' => 'app',
];
$config = array_replace($default, $userConfig);
print_r($config);
输出:
Array
(
[host] => 192.168.1.10
[port] => 3306
[user] => app
)
只覆盖用户指定的两项,port保留默认值。单层配置这样用没问题,多层记得换递归版本。
实例二:代码号学习编程·默认参数补全
<?php
$defaults = ['limit' => 20, 'offset' => 0, 'sort' => 'id'];
$input = ['limit' => 50, 'sort' => 'name'];
$params = array_replace($defaults, $input);
print_r($params);
输出:
Array
(
[limit] => 50
[offset] => 0
[sort] => name
)
接口参数处理里这个模式很常见:先铺默认值,再用入参覆盖,之后拿到的就是完整参数集。
实例三:代码号学习编程·多来源配置叠加
<?php
$base = ['debug' => false, 'cache' => true, 'log' => 'file'];
$env = ['debug' => true];
$cli = ['log' => 'stdout'];
$final = array_replace($base, $env, $cli);
print_r($final);
输出:
Array
(
[debug] => 1
[cache] => 1
[log] => stdout
)
优先级从右往左,越靠后的数组优先级越高。配置系统的分层覆盖就是这个思路。
七、踩坑记录
坑一:把array_replace()当成递归合并。嵌套数组会整体替换,不会逐层合并。多层结构必须用array_replace_recursive()。
坑二:数字键下标和array_merge()混用。需要保留下标语义时用了array_merge(),下标被重排,数据对不上。判断标准是"下标有没有业务含义"。
坑三:参数顺序颠倒。array_replace($override,$base)和array_replace($base,$override)结果不同。前者是"用base覆盖override",写反了逻辑正好反过来,而且代码看起来还挺合理,不容易发现。
坑四:以为会修改原数组。array_replace()返回新数组,原数组不变。如果后面继续用原数组,拿到的还是旧值。
坑五:传入非数组参数。参数中有非数组时返回null,后续对null做数组操作会报错。调用前应确保参数类型正确。
八、本节课程知识要点
-
array_replace()按"键"覆盖,同键替换,无键追加,不重排下标。
-
数字键和字符串键行为一致,这是与array_merge()的核心差异。
-
多个替换数组时,后面的覆盖前面的,顺序决定优先级。
-
嵌套数组不递归,整体替换;需要逐层覆盖用array_replace_recursive()。
-
返回新数组,原数组不变;参数非法时返回null。
-
只补缺失键、不覆盖已有键,用
+运算符更合适。
九、常见问题
问:array_replace()会改变原数组吗?
不会。它返回替换后的新数组,原数组保持原样。
问:数字键是怎么处理的?
同键覆盖,无键追加,不重新编号。数字下标会被保留。
问:和+运算符有什么区别?
+运算符是"左侧优先",同键时保留左侧的值;array_replace()是"右侧优先",同键时右侧覆盖左侧。
问:替换数组里的值为null会怎样?
会正常覆盖,键对应的值变成null。这和"键不存在"是两回事,不会触发保留原值的逻辑。
问:能用来做数组合并吗?
能,但要看数字键是否需要保留。下标无意义的列表合并,array_merge()更贴合语义。