← PHP pos()函数:current()的别名,读取数组当前指针元素 没有下一篇了 →

PHP prev()函数:数组内部指针回退一位的用法与边界处理

著
原创 2026-10-08 PHP 已有人查阅

一、prev()做的是反方向操作

next()把数组内部指针往前推一格,prev()反过来,把指针往回拉一格,然后返回拉过去之后那个元素的值。

函数原型:

mixed prev(array &$array);

参数是引用传递,必须传变量。返回类型mixed,有前一个元素就返回它的值,没有就返回false。

数组刚创建时,内部指针默认停在第一个元素。这时候调prev(),没有前一个元素,返回false,指针不会跑到数组外面去,还停在第一个元素。

看个基础对照:

$language = array("Java", "php", "python", "javascript");
echo next($language), "\n";  // php
echo prev($language), "\n";  // Java

next()先把指针从Java移到php并返回php。prev()再把指针拉回Java并返回Java。一进一退,回到原点。

二、prev()和next()的对称性

把current()、next()、prev()放一起,指针的移动轨迹就清楚了。

$language = array("Java", "php", "python", "javascript");

echo current($language), "\n"; // Java
echo next($language), "\n";    // php
echo prev($language), "\n";    // Java
echo current($language), "\n"; // Java

current()只读不动,停在Java。next()移到php并返回。prev()移回Java并返回。再current(),指针还在Java,所以还是Java。

再看连续next()之后prev()的表现:

$ocean = array("indian", "arctic", "antarctic", "pacific");

echo next($ocean), "\n";  // arctic
echo next($ocean), "\n";  // antarctic
echo prev($ocean), "\n";  // arctic

指针从indian走到arctic,再到antarctic,prev()拉回arctic。prev()和next()的步长都是1,方向相反,来回调用会在相邻两个元素之间摆动。

echo next($ocean), "\n";    // arctic
echo prev($ocean), "\n";    // indian
echo next($ocean), "\n";    // arctic
echo current($ocean), "\n"; // arctic

之后current()读的是arctic,因为指针停在那里没动。

这组函数的关系:

函数 指针动作 返回值
current() 不动 当前元素值
next() 前移一位 移动后的值
prev() 后移一位 移动后的值
reset() 移到开头 第一个元素值
end() 移到末尾 之后一个元素值

prev()是这张表里唯一往回走的。它的存在让手动遍历有了“回退”的能力。

三、边界行为:两端会卡住

指针在第一个元素时调prev(),返回false,指针留在第一个元素。指针在之后一个元素时调next(),返回false,指针留在之后一个元素。这个设计意味着指针不会越界,多次调用prev()不会出错。

$arr = array("code1", "code2");
var_dump(prev($arr)); // false,指针还在 code1
var_dump(prev($arr)); // false,还是 code1
echo current($arr);   // code1

prev()在开头卡住这件事,有个实际影响:如果你在循环里用prev()回退,回退到开头之后再回退就没有效果了,指针不会跑到负数位置。

用key()判断边界比看返回值可靠:

$arr = array("code1", "code2", "code3");
reset($arr);
while (key($arr) !== null) {
    $val = current($arr);
    // 处理
    next($arr);
}

key()在指针越界后返回null,而prev()返回false的情况要复杂一些——元素值是falsy时也返回false。两者的判断语义不同,混用容易出错。

四、prev()返回false的歧义

和next()一样,prev()返回false有两种可能:指针没有前一个元素,或者前一个元素的值本身就是false、0、""、null。

$data = array("code1", false, "code3");
next($data);  // 指针到 false
var_dump(prev($data)); // string(5) "code1"

这里prev()返回code1,没问题。但如果数组是:

$data = array(false, "code2", "code3");
next($data);
var_dump(prev($data)); // bool(false)

prev()返回false,但指针确实移到了第一个元素,只是那个元素的值是false。判断“是否真的没有前一个元素”不能只看返回值。

我在处理配置行解析时碰到过这个情况。配置数组里有一项是布尔false,表示某开关关闭。遍历时用prev()回退去读前一项,结果读到false就以为到头了,逻辑直接跳过。后来改成用key()判断指针位置,问题解决。

$config = array("debug" => false, "timeout" => 30, "retry" => 3);
end($config);
prev($config);
var_dump(key($config)); // "debug",指针确实在第一个元素

key()能明确告诉你指针在哪,比返回值靠谱。

五、项目里prev()的实际用法

解析带上下文的行。我做过一个读取自定义指令文件的小工具,每条指令可能引用上一行的变量。解析到某一行需要回看前一行时,prev()比较直接:

$lines = array("code1", "code2", "code3");
reset($lines);
while (($line = current($lines)) !== false) {
    if (strpos($line, "code3") === 0) {
        prev($lines);
        $prevLine = current($lines); // 回看上一行
    }
    next($lines);
}

这里有个细节:prev()之后current()读的是回退后的位置,处理完还要next()把指针推回原位,否则下一轮循环会重复处理。

从末尾往前找。用end()把指针移到末尾,再反复prev()往前遍历。适合从后往前找第一个满足条件的元素:

$records = array("code1" => 10, "code2" => 20, "code3" => 30);
end($records);
while (key($records) !== null) {
    if (current($records) > 15) {
        echo key($records); // code3
        break;
    }
    prev($records);
}

回退一步重新判断。表达式解析里,读到某个标记时可能需要回退到上一个token重新组合。prev()配合current()可以做这种“读一步、退一步”的控制。

一个踩坑记录。有次写遍历,逻辑是“遇到A就回退一步,把前一项和当前项合并处理”。代码里写的是while(($val=current($arr))!==false),数组里有一项值是"0","0"!==false成立,所以没出问题。但如果那一项是空字符串或布尔false,循环就会提前跳出。回退逻辑本身没错,错在把返回值当成“是否还有元素”的判断依据。后来统一改成key()判断,代码稳了。

不推荐用prev()做复杂遍历。内部指针是隐式状态,跨函数传递时容易被意外改动。如果遍历逻辑超过“读、判断、前进”三步,用索引变量或ArrayIterator更清楚。prev()适合局部、短距离的回退,不适合当遍历的主力。

六、和ArrayIterator的对比

PHP的SPL提供了ArrayIterator,它把指针状态封装在对象里,不会污染原数组的内部指针。

$arr = array("code1", "code2", "code3");
$it = new ArrayIterator($arr);
$it->next();
$it->prev();
echo $it->current(); // code1

ArrayIterator的current()、next()、prev()、key()和数组函数语义类似,但状态独立。同一个数组可以有多个迭代器同时遍历,互不干扰。数组内部指针做不到这一点——一个数组只有一个指针。

如果项目里需要多个游标、或者遍历状态要作为对象传递,ArrayIterator比prev()更合适。如果只是简单回退,prev()够用。

prev()的逻辑不复杂:指针回退一位,返回新位置的值,到头返回false。真正需要留意的是返回值false的歧义和指针在两端卡住的行为。判断是否还有前一个元素,用key()或指针位置,别只看返回值。实际项目里prev()多用于局部回退和从后往前找,不适合当遍历主力。内部指针是隐式状态,用得越少,代码越不容易出意外。

← PHP pos()函数:current()的别名,读取数组当前指针元素 没有下一篇了 →
分享笔记 (共有 篇笔记)
验证码:
微信公众号