PHP数组指针的异常现象。

5
$a=array('a','b','c','d');

while(key($a)!==NULL){
  echo key($a).'=>'.current($a).'<br/>';
  next ($a);
}

prev($a);
var_dump(current($a));

为什么var_dump返回false而不是"d"

我猜想一旦你到达数组的末尾,prev将不再起作用。但我不确定。 - Corbin
@Corbin 我想你是对的,尽管PHP开发人员并不惊讶地在文档中提到了这一点... - Alnitak
2个回答

4

这绝对是有意设计的。虽然我已经查阅了PHP文档,但未找到任何关于当通过next操作超出数组末尾后,指针变为无效,因此无法再使用prev的说明。不过,PHP源代码(zend_hash.c)清楚地解释了其中的原理。

ZEND_API int zend_hash_move_forward_ex(HashTable *ht, HashPosition *pos)
{
    HashPosition *current = pos ? pos : &ht->pInternalPointer;

    IS_CONSISTENT(ht);

    if (*current) {
        *current = (*current)->pListNext;
        return SUCCESS;
    } else
        return FAILURE;
}

ZEND_API int zend_hash_move_backwards_ex(HashTable *ht, HashPosition *pos)
{
    HashPosition *current = pos ? pos : &ht->pInternalPointer;

    IS_CONSISTENT(ht);

    if (*current) {
        *current = (*current)->pListLast;
        return SUCCESS;
    } else
        return FAILURE;
}

如您所见,zend_hash_move_backwards_ex(在PHP中映射为prev)在执行任何操作之前会测试当前指针是否有效,而zend_hash_move_forward_ex会将值设置为pListNext,在最后一个元素的情况下将是null
也就是说,与您可能期望的不同,nextprev并不仅仅是盲目地增加或减少C指针,然后检查结果来返回值或NULL,它们实际上是在增加或减少指针之前先检查指针。
这绝对是文档中的缺陷,肯定需要记录。正如另一个回复中提到的那样,您可以在循环遍历列表后使用end转到最后一个元素。
但是,您应该能够实现所需的逻辑(而无需使用end()),方法是在每次进展之前克隆指针,然后在到达数组末尾后使用克隆的指针。(但如果您已经知道prev()在已迭代数组的向后导航方面存在设计缺陷,那么没有真正好的理由这样做)

(离题:我很高兴看到尊重的PHP传统在底层C代码中使用不一致 函数名称仍然健在: zend_hash_move_forward_exzend_hash_move_backward*s*_ex。)


0
$a=array('a','b','c','d');

while(key($a)!==NULL){
  echo key($a).'=>'.current($a).'<br/>';
  next ($a);
}

prev($a);
var_dump(current($a));

在这段代码中,next返回下一个值并前进到下一个点,在循环结束时它给出最后一个元素,但指针前进到下一个即null。因此,您的var_dump(current($a));返回false
但是,
$a=array('a','b','c','d');

while(key($a)!==NULL){
  echo key($a).'=>'.current($a).'<br/>';
  next ($a);
}

//prev($a);
end(($a);
var_dump(current($a));

你将会得到你想要的元素d,因为它指向最后一个元素d。

我认为OP意识到了,真正的问题是当“next”到达数组末尾后为什么不能使用“prev”。 - Mahmoud Al-Qudsi
我已经解释了为什么他得到了错误的值。 - Rohit Choudhary

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接