数组访问与修改
概述
PHP 提供了多种方式来访问和修改数组元素,包括方括号语法、isset() 检查、array_key_exists() 验证、unset() 删除等。本章详细讲解数组元素访问与修改的各种操作方式及安全访问技巧。
基础概念
操作一览
| 操作 | 语法 | 说明 |
|---|---|---|
| 读取 | $arr['key'] | 通过键读取元素 |
| 写入 | $arr['key'] = 'val' | 修改或添加元素 |
| 追加 | $arr[] = 'val' | 末尾追加元素 |
| 删除 | unset($arr['key']) | 移除元素 |
| 检查 | isset($arr['key']) | 键存在且不为 null |
| 检查键 | array_key_exists('key', $arr) | 键存在(含 null) |
| 默认值 | $arr['key'] ?? 'default' | PHP 7.0+ 空合并运算符 |
语法与代码
基本访问与修改
php
<?php
declare(strict_types=1);
// 索引数组
$fruits = ['apple', 'banana', 'cherry'];
echo $fruits[0]; // apple
$fruits[1] = 'blueberry'; // 修改
$fruits[] = 'date'; // 追加
// 关联数组
$user = ['name' => 'Alice', 'age' => 30];
echo $user['name']; // Alice
$user['age'] = 31; // 修改
$user['role'] = 'admin'; // 添加
// 多维数组
$matrix = [[1, 2, 3], [4, 5, 6]];
echo $matrix[0][1]; // 2
$matrix[1][0] = 40; // 修改isset vs array_key_exists
php
<?php
declare(strict_types=1);
$arr = ['name' => 'Alice', 'age' => null];
// isset - 键存在且值不为 null
isset($arr['name']); // true
isset($arr['age']); // false(值为 null)
isset($arr['nonexistent']); // false
// array_key_exists - 仅检查键
array_key_exists('name', $arr); // true
array_key_exists('age', $arr); // true(键存在)
array_key_exists('nonexistent', $arr); // false
// PHP 7.0+ 空合并运算符
$arr['age'] ?? 'unknown'; // 'unknown'
$arr['name'] ?? 'unknown'; // 'Alice'
$arr['nonexistent'] ?? 'unknown'; // 'unknown'unset 删除元素
php
<?php
declare(strict_types=1);
$user = ['name' => 'Alice', 'age' => 30, 'email' => 'a@b.com'];
// 删除单个
unset($user['email']); // ['name' => 'Alice', 'age' => 30]
// 删除多个
unset($user['name'], $user['age']); // []
// 注意:删除后索引不连续
$nums = [0 => 'a', 1 => 'b', 2 => 'c'];
unset($nums[1]);
// [0 => 'a', 2 => 'c']
// 重新索引
$nums = array_values($nums);
// [0 => 'a', 1 => 'c']多维数组安全访问
php
<?php
declare(strict_types=1);
$company = [
'departments' => [
'engineering' => ['head' => 'Alice'],
],
];
// PHP 7.0+ 空合并运算符链
$head = $company['departments']['engineering']['head'] ?? 'N/A'; // Alice
$ceo = $company['departments']['executive']['head'] ?? 'N/A'; // N/A
// 安全获取嵌套值
function getNestedValue(array $array, string $key, mixed $default = null): mixed
{
$keys = explode('.', $key);
$current = $array;
foreach ($keys as $k) {
if (!is_array($current) || !array_key_exists($k, $current)) {
return $default;
}
$current = $current[$k];
}
return $current;
}
echo getNestedValue($company, 'departments.engineering.head'); // Alice数组引用赋值
php
<?php
declare(strict_types=1);
// 值复制(默认)
$a = [1, 2, 3];
$b = $a;
$b[0] = 99;
echo $a[0]; // 1(不受影响)
// 引用赋值
$a = [1, 2, 3];
$b = &$a;
$b[0] = 99;
echo $a[0]; // 99(被修改)详细说明
isset vs empty vs array_key_exists
php
<?php
declare(strict_types=1);
$arr = ['a' => 0, 'b' => '', 'c' => null, 'd' => false];
isset($arr['a']); // true
isset($arr['c']); // false
empty($arr['a']); // true(0 是 falsy)
empty($arr['b']); // true('' 是 falsy)
empty($arr['c']); // true(null 是 falsy)
array_key_exists('a', $arr); // true
array_key_exists('c', $arr); // true
array_key_exists('z', $arr); // falsePHP 8.0+ 未定义键行为
| 版本 | 访问不存在的键 |
|---|---|
| PHP < 8.0 | Notice,返回 null |
| PHP 8.0+ | Warning,返回 null |
php
<?php
declare(strict_types=1);
$arr = ['a' => 1];
// PHP 8.0+: Warning: Undefined array key "b"
// echo $arr['b'];
// 安全写法
$val = $arr['b'] ?? null;实战示例
点号语法配置读取器
php
<?php
declare(strict_types=1);
class Config
{
public function __construct(private array $data = []) {}
public function get(string $key, mixed $default = null): mixed
{
$keys = explode('.', $key);
$current = $this->data;
foreach ($keys as $k) {
if (!is_array($current) || !array_key_exists($k, $current)) {
return $default;
}
$current = $current[$k];
}
return $current;
}
public function set(string $key, mixed $value): void
{
$keys = explode('.', $key);
$this->data = $this->setNested($this->data, $keys, $value);
}
private function setNested(array $array, array $keys, mixed $value): array
{
$key = array_shift($keys);
if (empty($keys)) {
$array[$key] = $value;
} else {
$array[$key] = $this->setNested($array[$key] ?? [], $keys, $value);
}
return $array;
}
}
$config = new Config(['db' => ['host' => 'localhost', 'port' => 3306]]);
echo $config->get('db.host'); // localhost
echo $config->get('db.port'); // 3306
echo $config->get('db.name', 'app'); // app数组切片操作
php
<?php
declare(strict_types=1);
// array_slice - 截取数组的一部分
$fruits = ['apple', 'banana', 'cherry', 'date', 'elderberry'];
// 从偏移 1 开始取 3 个
$slice = array_slice($fruits, 1, 3);
// ['banana', 'cherry', 'date']
// 负偏移
$slice = array_slice($fruits, -3, 2);
// ['cherry', 'date']
// array_splice - 截取并替换(修改原数组)
$colors = ['red', 'green', 'blue', 'yellow', 'purple'];
$removed = array_splice($colors, 1, 2, ['cyan', 'magenta']);
// $colors: ['red', 'cyan', 'magenta', 'yellow', 'purple']
// $removed: ['green', 'blue']
// array_chunk - 将数组分割为多个块
$numbers = range(1, 10);
$chunks = array_chunk($numbers, 3);
// [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
// array_chunk 保留键名
$chunks = array_chunk($numbers, 3, true);
// [[0 => 1, 1 => 2, 2 => 3], [3 => 4, 4 => 5, 5 => 6], ...]
// array_pad - 填充数组到指定长度
$arr = ['a', 'b'];
$padded = array_pad($arr, 5, 'x');
// ['a', 'b', 'x', 'x', 'x'](右侧填充)
$padded = array_pad($arr, -5, 'x');
// ['x', 'x', 'x', 'a', 'b'](左侧填充)数组值检查
php
<?php
declare(strict_types=1);
// in_array - 检查值是否存在
$fruits = ['apple', 'banana', 'cherry'];
// 严格比较(推荐)
in_array('banana', $fruits, true); // true
in_array('BANANA', $fruits, true); // false(严格比较)
in_array('BANANA', $fruits, false); // true(松散比较,不推荐)
// array_search - 查找值并返回键
$key = array_search('cherry', $fruits, true);
echo $key; // 2
// 注意:array_search 返回 false 或键(可能是 0)
$key = array_search('apple', $fruits, true);
if ($key !== false) {
echo "Found at key: {$key}"; // 0
}
// in_array 的陷阱
in_array(0, ['foo', 'bar']); // false(严格模式)
in_array(0, ['foo', 'bar'], false); // true!(松散模式,0 == 'foo' 为 false... 实际为 true 取决于 PHP 版本)数组唯一化与去重
php
<?php
declare(strict_types=1);
// array_unique - 去除重复值
$data = [1, 2, 3, 2, 1, 4, 5, 3];
$unique = array_unique($data);
// [1, 2, 3, 4, 5](保留键名)
// array_unique 标志
$unique = array_unique($data, SORT_REGULAR);
// SORT_REGULAR: 比较值(默认)
// SORT_STRING: 作为字符串比较
// SORT_NUMERIC: 作为数字比较
// SORT_FLAG_CASE: 与 SORT_STRING 组合时忽略大小写
// 多维数组去重(基于某个字段)
$users = [
['id' => 1, 'name' => 'Alice'],
['id' => 2, 'name' => 'Bob'],
['id' => 1, 'name' => 'Alice Duplicate'],
];
$seen = [];
$unique = array_filter($users, function (array $user) use (&$seen): bool {
if (in_array($user['id'], $seen, true)) {
return false;
}
$seen[] = $user['id'];
return true;
});
print_r(array_values($unique));
// [['id' => 1, 'name' => 'Alice'], ['id' => 2, 'name' => 'Bob']]in_array 松散比较
in_array 默认使用松散比较。in_array('test', [0]) 在 PHP 8.0 以前返回 true(因为 0 == 'test')。PHP 8.0+ 修正了部分行为。始终使用 in_array($needle, $haystack, true) 进行严格比较。
数组切片与提取
php
<?php
declare(strict_types=1);
// array_slice 截取
$colors = ['red', 'green', 'blue', 'yellow', 'purple'];
echo implode(', ', array_slice($colors, 1, 3));
// green, blue, yellow
// array_splice 替换(修改原数组)
$items = ['a', 'b', 'c', 'd', 'e'];
$removed = array_splice($items, 1, 2, ['X', 'Y', 'Z']);
// $items: ['a', 'X', 'Y', 'Z', 'd', 'e']
// $removed: ['b', 'c']
// array_column 提取列
$users = [
['id' => 1, 'name' => 'Alice'],
['id' => 2, 'name' => 'Bob'],
];
$ids = array_column($users, 'id'); // [1, 2]
$map = array_column($users, 'name', 'id'); // [1 => 'Alice', 2 => 'Bob']注意事项
PHP 8.0+ 未定义键
PHP 8.0+ 将未定义数组键从 Notice 升级为 Warning。使用 ?? 运算符或 isset() 检查。
unset 后索引不连续
删除元素后索引不自动重排。需要连续索引时使用 array_values()。
最佳实践
- 用 ?? 获取带默认值元素:比三元运算符更简洁
- null 值用 array_key_exists:区分 null 和不存在的键
- 删除后用 array_values():重建连续索引
- 多维数组链式 ??:避免报错
- 避免引用赋值:除非确实需要