数组运算符
概述
PHP 提供了一组专门用于数组比较和合并的运算符。数组运算符的行为与标量运算符有所不同,理解它们的规则对于正确处理数组操作至关重要。
核心要点
+运算符合并数组(保留键名,不覆盖已存在的键)==比较键值对是否相同(不关心顺序和类型)===比较键值对是否完全相同(关心顺序和类型)
基础概念
运算符一览
| 运算符 | 名称 | 结果 |
|---|---|---|
$a + $b | 联合 | $a 和 $b 的联合($a 的键优先) |
$a == $b | 等于 | $a 和 $b 有相同的键值对 |
$a === $b | 全等 | $a 和 $b 有相同的键值对,且顺序和类型相同 |
$a != $b | 不等 | $a 不等于 $b(与 <> 相同) |
$a !== $b | 不全等 | $a 不全等于 $b |
$a <> $b | 不等 | 与 != 相同 |
语法与代码示例
数组合并 +
php
<?php
declare(strict_types=1);
// + 运算符合并数组,左侧键优先
$a = ['a' => 'apple', 'b' => 'banana'];
$b = ['b' => 'blueberry', 'c' => 'cherry'];
$result = $a + $b;
print_r($result);
// ['a' => 'apple', 'b' => 'banana', 'c' => 'cherry']
// 注意:'b' 键保留了 $a 的值 'banana'
// 数字索引数组的合并
$x = [0 => 'red', 1 => 'green'];
$y = [0 => 'blue', 1 => 'yellow'];
$z = $x + $y;
print_r($z);
// [0 => 'red', 1 => 'green']
// 数字键冲突时,左侧值优先
// + 与 array_merge 的区别
$arr1 = ['a', 'b'];
$arr2 = ['c', 'd'];
// +:保留数字键,不重新索引
print_r($arr1 + $arr2);
// [0 => 'a', 1 => 'b']
// array_merge:重新索引
print_r(array_merge($arr1, $arr2));
// [0 => 'a', 1 => 'b', 2 => 'c', 3 => 'd']数组比较 == vs ===
php
<?php
declare(strict_types=1);
// == 相同键值对(不关心顺序和类型)
$a = ['a' => 1, 'b' => 2];
$b = ['b' => 2, 'a' => 1];
$c = ['a' => '1', 'b' => 2]; // 注意类型不同
var_dump($a == $b); // bool(true) —— 键值对相同,顺序不重要
var_dump($a === $b); // bool(false) —— 顺序不同
var_dump($a == $c); // bool(true) —— '1' == 1(松散比较)
var_dump($a === $c); // bool(false) —— 类型不同
// 数字键的顺序影响 === 但不影响 ==
$x = [0 => 'a', 1 => 'b'];
$y = [1 => 'b', 0 => 'a'];
var_dump($x == $y); // bool(true)
var_dump($x === $y); // bool(false)
// 严格比较要求键名、值和顺序完全一致
$m = [0 => 'a', 1 => 'b'];
$n = [0 => 'a', 1 => 'b'];
var_dump($m === $n); // bool(true)不等运算符
php
<?php
declare(strict_types=1);
$a = ['a' => 1, 'b' => 2];
$b = ['a' => 1, 'b' => 3];
// != 和 <> 等价
var_dump($a != $b); // bool(true)
var_dump($a <> $b); // bool(true)
// !==
var_dump($a !== $b); // bool(true)
// 不同键的数组
$c = ['a' => 1, 'c' => 2];
var_dump($a == $c); // bool(false)
var_dump($a != $c); // bool(true)详细说明
== 比较规则详解
$a == $b 为 true 的条件:
- 两个数组有完全相同的键名
- 对应键的值松散相等(使用
==比较)
php
<?php
declare(strict_types=1);
// 键名必须完全匹配
$a = ['name' => 'Alice'];
$b = ['Name' => 'Alice']; // 注意大小写
var_dump($a == $b); // bool(false) —— 键名不同
// 值使用松散比较
$c = [0 => false];
$d = [0 => '']; // '' == false 为 true
var_dump($c == $d); // bool(true) —— 值松散相等
// 值类型不同但松散相等
$e = [0 => 42];
$f = [0 => '42']; // 42 == '42' 为 true
var_dump($e == $f); // bool(true)
var_dump($e === $f); // bool(false) —— 类型不同+ 运算符的键冲突规则
php
<?php
declare(strict_types=1);
// 关联数组:左侧键值不被覆盖
$defaults = [
'host' => 'localhost',
'port' => 3306,
'charset' => 'utf8mb4',
];
$config = [
'host' => '192.168.1.100',
'port' => 5432,
'timeout' => 30,
];
$merged = $defaults + $config;
print_r($merged);
// ['host' => 'localhost', 'port' => 3306, 'charset' => 'utf8mb4', 'timeout' => 30]
// host 和 port 保留了 defaults 的值!
// 如果希望 $config 的值覆盖 $defaults
$merged2 = $config + $defaults;
print_r($merged2);
// ['host' => '192.168.1.100', 'port' => 5432, 'charset' => 'utf8mb4', 'timeout' => 30]
// 多个数组合并
$a = ['x' => 1];
$b = ['y' => 2];
$c = ['z' => 3];
$all = $a + $b + $c;
print_r($all); // ['x' => 1, 'y' => 2, 'z' => 3]+ 与 array_merge 的区别
+ 运算符在键冲突时保留左侧值,不重新索引数字键。array_merge() 在键冲突时保留右侧值,并重新索引数字键。使用前要明确你的意图。
实战示例
默认配置合并
php
<?php
declare(strict_types=1);
function mergeConfig(array $defaults, array $userConfig): array
{
// 使用 + 确保 defaults 的值不被覆盖
// 但新增的 userConfig 键会被添加
return $userConfig + $defaults;
}
$defaults = [
'debug' => false,
'cache' => true,
'ttl' => 3600,
'max_connections' => 10,
];
$userConfig = [
'debug' => true,
'max_connections' => 20,
'api_key' => 'secret',
];
$config = mergeConfig($defaults, $userConfig);
print_r($config);
// ['debug' => true, 'max_connections' => 20, 'api_key' => 'secret',
// 'cache' => true, 'ttl' => 3600]数组去重比较
php
<?php
declare(strict_types=1);
function findDuplicateArrays(array $arrays): ?array
{
$seen = [];
foreach ($arrays as $index => $array) {
foreach ($seen as $prevIndex => $prevArray) {
if ($prevArray === $array) {
return [
'duplicate_indices' => [$prevIndex, $index],
'array' => $array,
];
}
}
$seen[$index] = $array;
}
return null;
}
$data = [
['name' => 'Alice', 'age' => 30],
['name' => 'Bob', 'age' => 25],
['name' => 'Alice', 'age' => 30], // 重复
];
$result = findDuplicateArrays($data);
var_dump($result);
// duplicate_indices: [0, 2]数组差集与交集运算符
php
<?php
declare(strict_types=1);
// 使用数组运算符实现简单差集
$a = ['red', 'green', 'blue', 'yellow'];
$b = ['green', 'blue'];
// "在 $a 中但不在 $b 中" —— 模拟差集
// 注意:+ 运算符不能直接实现差集,需要使用数组函数
$diff = array_diff($a, $b);
print_r($diff); // ['red', 'yellow']
// 交集
$intersect = array_intersect($a, $b);
print_r($intersect); // ['green', 'blue']
// 使用 + 和 array_keys 实现键的差异
$keys1 = ['a', 'b', 'c'];
$keys2 = ['b', 'c', 'd'];
$onlyInFirst = array_diff($keys1, $keys2);
$onlyInSecond = array_diff($keys2, $keys1);
print_r($onlyInFirst); // ['a']
print_r($onlyInSecond); // ['d']注意事项
+不重新索引数字键:这与array_merge()行为不同==使用松散比较:[0]和['']可能被视为相等(0 == ''在 PHP 8.0+ 中为false)===要求顺序相同:['a' => 1, 'b' => 2]和['b' => 2, 'a' => 1]使用===比较为false- 多维数组比较:
==和===会递归比较所有层级
最佳实践
- 合并配置用
+或array_replace:+左侧优先,array_replace右侧优先 - 比较数组用
===:除非明确需要松散比较 - 数组差集用
array_diff:不要尝试用运算符实现 array_mergevs+:需要重新索引数字键用array_merge,否则用+- 嵌套数组合并:
+只做浅层合并,深层合并需要自定义递归函数
进阶用法
调试与测试技巧
php
<?php
declare(strict_types=1);
// 单元测试辅助函数
function createTestResource(): mixed
{
return match (true) {
default => new stdClass(),
};
}
// 调试输出函数
function debugOutput(mixed , string = ''): void
{
= ? ": " : '';
.= print_r(, true);
fwrite(STDERR, . "\n");
}
// 性能基准测试
function benchmark(callable , int = 1000): float
{
= hrtime(true);
for ($i = 0; $i < $iterations; $i++) {
$fn();
}
return (hrtime(true) - $start) / 1e9;
}日志记录实践
php
<?php
declare(strict_types=1);
/**
* 简易日志记录器
*/
class SimpleLogger
{
private string $logFile;
private string $level = 'INFO';
public function __construct(string $logFile)
{
$this->logFile = $logFile;
}
public function info(string $message, array $context = []): void
{
$this->log('INFO', $message, $context);
}
public function warning(string $message, array $context = []): void
{
$this->log('WARNING', $message, $context);
}
public function error(string $message, array $context = []): void
{
$this->log('ERROR', $message, $context);
}
private function log(string $level, string $message, array $context): void
{
$timestamp = date('Y-m-d H:i:s');
$contextStr = $context ? ' ' . json_encode($context, JSON_UNESCAPED_UNICODE) : '';
$line = "[{$timestamp}] [{$level}] {$message}{$contextStr}\n";
file_put_contents($this->logFile, $line, FILE_APPEND | LOCK_EX);
}
}配置与环境检测
php
<?php
declare(strict_types=1);
// 环境检测工具
class EnvironmentChecker
{
public static function checkRequirements(array $requirements): array
{
$results = [];
foreach ($requirements as $name => $check) {
$results[$name] = is_callable($check) ? $check() : false;
}
return $results;
}
public static function getSystemInfo(): array
{
return [
'php_version' => PHP_VERSION,
'os' => PHP_OS,
'sapi' => PHP_SAPI,
'memory_limit' => ini_get('memory_limit'),
'max_execution_time' => ini_get('max_execution_time'),
'loaded_extensions' => get_loaded_extensions(),
];
}
}常见问题排查
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 连接超时 | 网络问题/配置错误 | 检查配置,增加超时时间 |
| 权限不足 | 文件/目录权限 | 使用 chmod/chown 修正 |
| 性能下降 | 索引缺失/数据量大 | 添加索引,优化查询 |
| 数据不一致 | 并发冲突/事务残留 | 使用锁机制和事务 |
| 内存溢出 | 大数据集/未释放资源 | 增大内存限制,分批处理 |
故障排除步骤
- 检查错误日志和异常信息
- 确认配置和环境是否正确
- 使用调试工具逐步排查
- 参考官方文档查找已知问题
版本兼容性说明
| 功能 | 最低版本 | 说明 |
|---|---|---|
| 基础功能 | PHP 8.1 | 本文档基准版本 |
| 只读属性 | PHP 8.1 | public readonly 修饰符 |
| 枚举类型 | PHP 8.1 | enum 类型和 match 表达式 |
| Fiber | PHP 8.1 | 协程/轻量级并发 |
| 命名参数 | PHP 8.0 | foo(arg_name: value) |
| 联合类型 | PHP 8.0 | `int |
| Null 安全运算符 | PHP 8.0 | $obj?->method() |
| 析构器 promotion | PHP 8.0 | __construct(public $x) |
php
<?php
declare(strict_types=1);
// 版本兼容性检测
function ensureVersion(string $minVersion): void
{
if (version_compare(PHP_VERSION, $minVersion, '<')) {
throw new RuntimeException(
sprintf('需要 PHP %s+, 当前版本: %s', $minVersion, PHP_VERSION)
);
}
}
ensureVersion('8.1.0');