從 PHP 7.2 開始,函式 "each" 已被棄用,因此我發布的 has_next 不再是好主意。還有另一種方法可以保持簡單和快速
<?php
function has_next(array $_array)
{
return next($_array) !== false ?: key($_array) !== null;
}
?>
(PHP 4, PHP 5, PHP 7, PHP 8)
next — 將陣列的內部指標向前移動
next() 的行為類似 current(),但有一個差異。它會在返回元素值之前,將內部陣列指標向前移動一個位置。這表示它會返回下一個陣列值,並將內部陣列指標向前移動一個。
返回內部陣列指標所指向的下一個位置的陣列值,如果沒有更多元素,則返回 false
。
版本 | 描述 |
---|---|
8.1.0 | 在 object 上呼叫此函式已被棄用。請先使用 get_mangled_object_vars() 將 object 轉換為 array,或者使用實作 Iterator 介面的類別所提供的函式,例如 ArrayIterator。 |
7.4.0 | SPL 類別的實例現在被視為沒有屬性的空物件,而不是呼叫與此函式名稱相同的 Iterator 方法。 |
範例 #1 next() 及其相關函式的範例用法
<?php
$transport = array('foot', 'bike', 'car', 'plane');
$mode = current($transport); // $mode = 'foot';
$mode = next($transport); // $mode = 'bike';
$mode = next($transport); // $mode = 'car';
$mode = prev($transport); // $mode = 'bike';
$mode = end($transport); // $mode = 'plane';
?>
從 PHP 7.2 開始,函式 "each" 已被棄用,因此我發布的 has_next 不再是好主意。還有另一種方法可以保持簡單和快速
<?php
function has_next(array $_array)
{
return next($_array) !== false ?: key($_array) !== null;
}
?>
不要將 next 與 continue 混淆!
如果您是一位剛開始使用 PHP 的 Perl 開發人員,您可能會嘗試在迴圈內使用 "next" 來跳到下一次迭代...
例如,
foreach ($things as $thing) {
if (something I don't like about $thing) {
next;
}
blah....
}
php 編譯器會接受 next... 但它不會起作用。
請改用此方法
foreach ($things as $thing) {
if (something I don't like about $thing) {
continue;
}
blah....
}
此程式碼會返回指定鍵的鄰居。如果沒有鄰居,結果將為空。我的方法是使用鍵的順序來確定鄰居,這與僅獲取陣列中的下一個/上一個元素不同。歡迎指出愚蠢之處 :)
<?php
function array_neighbor($arr, $key)
{
krsort($arr);
$keys = array_keys($arr);
$keyIndexes = array_flip($keys);
$return = array();
if (isset($keys[$keyIndexes[$key]-1]))
$return[] = $keys[$keyIndexes[$key]-1];
if (isset($keys[$keyIndexes[$key]+1]))
$return[] = $keys[$keyIndexes[$key]+1];
return $return;
}
?>
此函數將會回傳一個關聯陣列中,指定條目的前一個與後一個相鄰元素。如果指定的 $key 指向陣列的最後一個或第一個元素,則會依序回傳陣列的第一個或最後一個鍵。這是先前發布的相同函數的改進版本。
<?php
function array_neighbor($count, $key = null, $arRelated = array(), $cntRelated = 2)
{
if($count > 0 && isset($key))
{
$keyL = $count - 1;
$keyR = 1;
$arResult = array();
for($i = 1; $i <= $cntRelated; $i++)
{
if($key == 0)
{
if(($i % 2) == 0)
{
$curKey = $count - $keyL;
$keyL--;
}
else
{
$curKey = $count - $keyR;
$keyR++;
}
}
else
{
if($arRelated[$i] >= $count - 1)
{
$curKey = 0;
}
else
{
$curKey = $arRelated[$i] + 1;
}
}
$arResult[$i] = $curKey;
}
return $arResult;
}
}
$arr = range(0, 4);
$count = count($arr);
foreach($arr as $key => $v)
{
if($arRelated = array_neighbor($count, $key, $arRelated))
{
$arHeighbor[$key]['RELATED'] = $arRelated;
}
}
echo '<pre>';print_r($arHeighbor); echo '</pre>';
?>
Array
(
[0] => Array
(
[RELATED] => Array
(
[1] => 4
[2] => 1
)
)
[1] => Array
(
[RELATED] => Array
(
[1] => 0
[2] => 2
)
)
[2] => Array
(
[RELATED] => Array
(
[1] => 1
[2] => 3
)
)
[3] => Array
(
[RELATED] => Array
(
[1] => 2
[2] => 4
)
)
[4] => Array
(
[RELATED] => Array
(
[1] => 3
[2] => 0
)
)
)
Papipo 在下方提供的函數概念很有用,但無法運作。
「由於您沒有使用傳參考的方式傳遞陣列,其指標僅在函數內移動。」
這是真的,但是您在 has_next() 函數中操作的陣列,其指標將會設定在第一個元素,而不是與原始陣列相同的位置。您應該做的是透過傳參考的方式,將陣列傳遞給 has_next() 函數。在 has_next() 函數中,建立要處理的陣列副本。找出原始陣列的當前指標位置,並將工作副本上的指標設定在相同的元素。然後,您可以測試該陣列是否有「下一個」元素。
請嘗試以下替代方案
<?php
function has_next(&$array)
{
$A_work=$array; //$A_work 是 $array 的副本,但其內部指標設定在第一個元素。
$PTR=current($array);
array_set_pointer($A_work, $PTR);
if(is_array($A_work))
{
if(next($A_work)===false)
return false;
else
return true;
}
else
return false;
}
function array_set_pointer(&$array, $value)
{
reset($array);
while($val=current($array))
{
if($val==$value)
break;
next($array);
}
}
?>
PHP:5.2.10-2ubuntu6.3(在實際的 Jaunty 9.10 Ubuntu 發行版上預設 apt-get 安裝 - 請參閱日期 - G33kWoRDs)
如果您複製陣列,請注意您的陣列指標 - 指標也會被複製。
例如,如果您有此結構
<?php
$array = array('zero','one','two','three','four','five','six','seven');
$array2 = $array;
next($array);
echo key($array);
echo key($array2);
// 將輸出:
// 1
// 0
?>
但是,如果在您設定指標後複製陣列,指標也會被複製
<?php
$array = array('zero','one','two','three','four','five','six','seven');
next($array);
$array2 = $array;
echo key($array);
echo key($array2);
// 將輸出:
// 1
// 1
?>
更重要的是,foreach 不會在遍歷後重設指標
<?php
$array = array('zero','one','two','three','four','five','six','seven');
next($array);
$array2 = array();
foreach($array AS $key => $value){
echo $key;
$array2[$key] = $value;
}
echo var_dump(key($array));
echo key($array2);
// foreach 的輸出結果會是:
// 0 1 2 3 4 5 6 7
// 而 key 的輸出結果會是:
// NULL
// 0
?>
在遍歷之後,php 函式似乎會重置指定位置的指標(我不清楚內部的處理方式 - 也可能使用了陣列的副本)。
<?php
$array = array('zero','one','two','three','four','five','six','seven');
next($array);
$array2 = array_values($array);
echo key($array);
echo key($array2);
// 輸出結果會是:
// 1
// 0
?>
有很多像 array_merge($array) 這類的方法,既不會重置 $array 的指標,也不會將指標複製到 $array2。請注意這一點。
希望這對您有所幫助。
當使用 foreach 取代使用 reset()/next() 的程式碼時,請務必小心,因為 foreach 不會更新陣列的內部指標。這表示您無法在 foreach 迴圈中使用 next() 來跳過一個元素,或是在函式中使用 current() 來取得目前元素的參考。您可能會有程式碼依賴這個內部指標,而替換它會比您預期的更費力。
請參閱 https://php.dev.org.tw/foreach
我建議在文件主體的最上方加入一個警告,指出不應該在 foreach 迴圈中使用 next()。以前似乎有提到過,但我花了數小時才解決這種組合所造成的怪異問題,最後才在另一個網站上偶然發現線索,這似乎表明它原本是清楚標示的。如果您仔細尋找,可以在一些註釋中找到這個問題的參考,但人們不會期望在這種基本的事情上尋找這些註釋。
我需要知道陣列是否有更多項目,但不要移動陣列的內部指標。也就是說,需要一個 has_next() 函式。
<?php
function has_next($array) {
if (is_array($array)) {
if (next($array) === false) {
return false;
} else {
return true;
}
} else {
return false;
}
}
$array = array('fruit', 'melon');
if (has_next($array)) {
echo next($array);
}
// 輸出 'melon'
?>
由於您沒有使用傳參考的方式傳遞陣列,因此其指標只會在函式內部移動。
希望這有幫助。
一個更易讀的 papipo has_next 函式版本
<?php
function has_next($array) {
$has_next = is_array($array) && next($array) !== false;
return $has_next;
}
?>
或是
<?php
function has_next($array) {
$has_next = false;
if(is_array($array)) {
$has_next = next($array) !== false;
}
return $has_next;
}
?>
這是一個很好的範例,說明如何從 php key() 手冊中使用 current() 和 next() 函式來迴圈陣列。我認為這個特定的範例放在 current() 和 next() 手冊中會比放在 key() 手冊中更適合。
<?php
$array = array(
'fruit1' => 'apple',
'fruit2' => 'orange',
'fruit3' => 'grape',
'fruit4' => 'apple',
'fruit5' => 'apple');
// 這個迴圈會輸出所有值為 "apple" 的關聯陣列的鍵
reset($array); // 準備迴圈的陣列
while ($fruit_name = current($array)) {
if ($fruit_name == 'apple') {
echo key($array), "\n";
}
next($array);
}
?>
請注意!使用 next() 和 prev() 有可能會遺失陣列指標。
<?php
// 範例
$array = array(
'fruit1' => 'apple',
'fruit2' => 'orange',
'fruit3' => 'grape',
'fruit4' => 'apple',
'fruit5' => 'apple');
reset($array); // 準備陣列
$row = current($array);
var_dump($row); // 'apple'
$row = prev($array);
var_dump($row); // false。陣列指標遺失了!
$row = next($array); // 無法返回上一個 (第一個/最後一個元素)!
var_dump($row); // false
?>
這是迴圈中使用 next 的最佳範例
<?php
$array = array(
'fruit1' => 'apple',
'fruit2' => 'orange',
'fruit3' => 'grape',
'fruit4' => 'apple',
'fruit5' => 'apple');
// 這個迴圈會輸出所有值為 "apple" 的關聯陣列的鍵
reset($array); // 準備迴圈的陣列
while ($fruit_name = current($array)) {
if ($fruit_name == 'apple') {
echo key($array), "\n";
}
next($array);
}
reset($array);
?>
此函數將會回傳一個關聯陣列中,指定條目的前一個與後一個相鄰元素。如果指定的 $key 指向陣列的最後一個或第一個元素,則會依序回傳陣列的第一個或最後一個鍵。這是先前發布的相同函數的改進版本。
<?php
function array_neighbor($arr, $key)
{
$keys = array_keys($arr);
$keyIndexes = array_flip($keys);
$return = array();
if (isset($keys[$keyIndexes[$key]-1])) {
$return[] = $keys[$keyIndexes[$key]-1];
}
else {
$return[] = $keys[sizeof($keys)-1];
}
if (isset($keys[$keyIndexes[$key]+1])) {
$return[] = $keys[$keyIndexes[$key]+1];
}
else {
$return[] = $keys[0];
}
return $return;
}
?>
此函式會回傳陣列中指定鍵之後的下一個元素,如果此鍵為最後一個元素或不存在於陣列中,則回傳 false。
<?php
function nextElement(array $array, $currentKey)
{
if (!isset($array[$currentKey])) {
return false;
}
$nextElement = false;
foreach ($array as $key => $item) {
$nextElement = next($array);
if ($key == $currentKey) {
break;
}
}
return $nextElement;
}
此類別實作了陣列的簡單操作
<?php
class Steps {
private $all;
private $count;
private $curr;
public function __construct () {
$this->count = 0;
}
public function add ($step) {
$this->count++;
$this->all[$this->count] = $step;
}
public function setCurrent ($step) {
reset($this->all);
for ($i=1; $i<=$this->count; $i++) {
if ($this->all[$i]==$step) break;
next($this->all);
}
$this->curr = current($this->all);
}
public function getCurrent () {
return $this->curr;
}
public function getNext () {
self::setCurrent($this->curr);
return next($this->all);
}
}
?>
使用範例
<?php
$steps = new Steps();
$steps->add('one');
$steps->add('two');
$steps->add('three');
$steps->setCurrent('one');
echo $steps->getCurrent()."<br />";
echo $steps->getNext()."<br />";
$steps->setCurrent('two');
echo $steps->getCurrent()."<br />";
echo $steps->getNext()."<br />";
?>
關於使用 foreach 的參考,您可以直接使用它們。避免許多文章中提供的許多「解決方法」。
$array = array(1,2,3,4,5);
foreach($array as &$value)
或使用 $key
foreach($array as $key => $value)
{
$array[$key] = '...';
}
brentimus 的 array_set_pointer 函式只有在陣列值在陣列中是唯一且沒有任何陣列值為 FALSE 時才會起作用。使用 key() 而不是 current() 會更可靠。基於類似的原因,在呼叫 next() 之後檢查 key() 以判斷 next() 元素是否「存在」會更好。單純檢查 next() 回傳的值在查看陣列的第一個元素時會產生偽陰性,例如:['one', 0, 'three']
然而,事實證明,複製的陣列會保留原始陣列的指標,因此這裡實際上不需要 array_set_pointer。以下程式碼應該可以運作
<?php
function has_next(array &$array) {
$A_work = $array; // $A_work 是 $array 的副本,包含其內部指標。
next($A_work);
if (key($A_work) === NULL)
return false;
else
return true;
}
?>
在處理 next() 在陣列中沒有其他元素時或元素本身為 FALSE 時會回傳 FALSE 的事實之後,我終於找到一種可以執行永遠不會失敗的 has_next() 方法的方式。您可以忽略和/或反對我最後的評論,它將會被刪除。
以下是可運作的程式碼
<?php
function has_next(array $a){
return next($a) !== false ?: each($a) !== false;
}
?>