想拿到数组的之后一个键名,PHP 7.3之前得绕一圈:先用end()把指针移到之后一个,再用key()拿键名——但这样会移动数组内部指针。或者用array_keys()拿所有键名再取之后一个——但这样会创建新数组,浪费内存。
array_key_last()就是来解决这个问题的:直接返回数组的之后一个键名,不移动指针,不创建新数组。
语法格式
mixed array_key_last(array $array): mixed
参数说明:
| 参数 | 说明 | 必填? |
|---|---|---|
| array | 要操作的数组 | 必填 |
返回值:
-
数组不为空时,返回之后一个键名
-
数组为空时,返回
null
老办法的问题
PHP 7.3之前,获取数组之后一个键名的几种方式都有弊端:
// 方式一:移动指针
end($array);
$last_key = key($array);
// 问题:数组内部指针被移动了,影响后续代码
// 方式二:取所有键名
$keys = array_keys($array);
$last_key = end($keys);
// 问题:创建了一个新数组,大数组时内存消耗大
// 方式三:foreach循环
foreach ($array as $key => $value) {
$last_key = $key;
}
// 问题:需要遍历整个数组,O(n)复杂度
array_key_last()一行搞定,O(1)复杂度,不移动指针,不复制数组。
示例1:关联数组
<?php
$student = [
"id" => 1001,
"name" => "张伟",
"score" => 85,
"class" => "软件工程"
];
$last_key = array_key_last($student);
echo "之后一个键名:{$last_key}\n";
echo "对应的值:{$student[$last_key]}\n";
// 验证原数组指针没有被移动
echo "当前指针指向的值:" . current($student) . "\n";
?>
输出:
之后一个键名:class
对应的值:软件工程
当前指针指向的值:1001
指针仍然在第一个元素,没有被array_key_last()影响。
示例2:索引数组
<?php
$colors = ["红色", "绿色", "蓝色", "黄颜色"];
$last_key = array_key_last($colors);
echo "之后一个键名:{$last_key}\n";
echo "之后一个值:{$colors[$last_key]}\n";
?>
输出:
之后一个键名:3
之后一个值:黄颜色
索引数组的键名就是数字下标。长度为4的数组,之后一个键名是3(从0开始)。
示例3:键名不连续或非0起始
<?php
$data = [
5 => "第五个",
10 => "第十个",
15 => "第十五个",
20 => "第二十个"
];
$last_key = array_key_last($data);
echo "之后一个键名:{$last_key}\n";
echo "之后一个值:{$data[$last_key]}\n";
?>
输出:
之后一个键名:20
之后一个值:第二十个
即使键名不连续、不是从0开始,array_key_last()也能正确返回定义顺序中的之后一个键名(不是数值较大的那个)。
示例4:空数组
<?php
$empty = [];
$last_key = array_key_last($empty);
var_dump($last_key);
if ($last_key === null) {
echo "数组是空的\n";
}
?>
输出:
NULL
数组是空的
空数组返回null,需要做判断处理。
个人经验分享
-
和array_key_first()是搭档
PHP 7.3同时引入了array_key_first()和array_key_last(),一个拿第一个键名,一个拿之后一个键名。 -
为什么不用end() + key()?
// 老方法 end($array); $last_key = key($array); // 指针被移到了之后,后续代码如果依赖指针位置会出问题 // 新方法 $last_key = array_key_last($array); // 指针纹丝不动 -
为什么不用array_keys()?
// 老方法:100万元素的数组,array_keys会创建一个100万长度的新数组 $keys = array_keys($huge_array); $last_key = end($keys); // 新方法:直接返回,零拷贝 $last_key = array_key_last($huge_array);内存和性能的差距在大数组上非常明显。
-
PHP版本要求
array_key_last()需要PHP 7.3.0及以上。如果项目还需要支持低版本,可以自己写一个兼容函数。
示例5:代码号学习编程场景
<?php
// 场景:消息队列,获取新一条消息的ID
$messages = [
"msg_001" => ["text" => "第一条消息", "time" => "09:00"],
"msg_002" => ["text" => "第二条消息", "time" => "10:30"],
"msg_003" => ["text" => "第三条消息", "time" => "14:15"],
"msg_004" => ["text" => "第四条消息", "time" => "16:45"]
];
$latest_msg_id = array_key_last($messages);
$latest_msg = $messages[$latest_msg_id];
echo "新消息ID:{$latest_msg_id}\n";
echo "内容:{$latest_msg['text']}\n";
echo "时间:{$latest_msg['time']}\n";
?>
输出:
新消息ID:msg_004
内容:第四条消息
时间:16:45
示例6:PHP 7.3以下版本的兼容实现
<?php
// 兼容PHP 7.3以下版本的polyfill
if (!function_exists('array_key_last')) {
function array_key_last(array $array) {
if (empty($array)) {
return null;
}
// 方法一:使用end()但会移动指针,需要reset恢复
$last_key = key($array);
end($array);
$last_key = key($array);
reset($array); // 恢复指针位置
return $last_key;
// 或者方法二:用foreach遍历(不移动指针但O(n))
// foreach ($array as $key => $value) {
// $last_key = $key;
// }
// return $last_key;
}
}
// 现在可以放心使用了
$data = ["a" => 1, "b" => 2, "c" => 3];
echo "之后一个键名:" . array_key_last($data) . "\n";
?>
注意:上面这个polyfill为了不改变指针用了reset(),但如果原数组指针本来在别的位罝,reset()会改变它。更干净的polyfill应该用foreach,虽然O(n)但兼容性更好。
示例7:配合array_key_first取首尾
<?php
$queue = [
"Q001" => ["task" => "发送邮件", "status" => "pending"],
"Q002" => ["task" => "生成报表", "status" => "processing"],
"Q003" => ["task" => "备份数据", "status" => "completed"],
"Q004" => ["task" => "清理缓存", "status" => "pending"]
];
$first_id = array_key_first($queue);
$last_id = array_key_last($queue);
echo "队列第一个任务ID:{$first_id}\n";
echo "队列之后一个任务ID:{$last_id}\n";
// 判断是否只有一个任务
if ($first_id === $last_id && !empty($queue)) {
echo "队列中只有一个任务\n";
} else {
echo "队列中有多个任务\n";
}
?>
输出:
队列第一个任务ID:Q001
队列之后一个任务ID:Q004
队列中有多个任务
本节课程知识要点
-
array_key_last()返回数组的之后一个键名,不改变原数组 -
空数组返回
null -
PHP 7.3.0正式引入
-
相比
end()+key():不移动内部指针 -
相比
array_keys($arr)[-1]或end(array_keys($arr)):不创建新数组,内存效率高 -
O(1)时间复杂度,大数组表现优秀
-
配合
array_key_first()可以快速获取首尾键名 -
低版本PHP可以自己实现polyfill