Detecting the "actual" end of an array in PHP
Given I have an array as follows:
$array = array('a', 'b', 0, 'c', null, 'd');
Now, I can iterate through it easily with foreach
of course:
foreach($array as $value){
var_dump($value);
}
And all is fine and well. However, if I want to do a "peek" to see if I'm on the last element, the following won't work:
reset($array);
while($value = current($array)){
var_dump($value);
if(next($array)){
// this won't be accurate because of the 0 element
}
}
Ok, so I do a stricter test:
if(null !== next($array)){
// this STILL won't be accurate because of the null element
}
Is the only solution to use an indexed for
loop with a arithmetic peeking? I don't see this as being viable for maintaining associative key integrity without a lot of goofing around. (I'm aware my example doesn't exemplify this caveat, but I'd swap current()
for each()
, and next()
for current()
)
Is there no foolproof way to accurately determine whether the array pointer has moved past the end of the array, regardless of array element values (null
, 0
, etc.)
Caveat; While of course there are plenty of solutions that exist using temporary variables, it just seems both filthy and silly that such a thing would be necessitated for this operation. I'm surprised no concise solutions exists.
Well, this is by no means a perfect solution, since Note but here goes:array_keys()
is creating a new array
$array = array('alpha', 'b' => 'beta', null, 'g' => 'gamma', false, 0, 'delta', null);
list($end) = array_keys(array_slice($array, -1, 1, true));
foreach($array as $key => &$value){
// do important stuff on each element
if($key !== $end){
// do important stuff on all but last element
}
}
NoteI swapped out array_slice()
and array_keys()
so a full key-copy isn't created. It was initially: array_slice(array_keys($array), -1开发者_StackOverflow社区);
, seems like the revision would be better on memory.
Another edit for those who stumble here; these may be of use in similar situations:
// each returns the current element, but assigns to the referenced arguments
// the "peeked" values. they're missing checks, but it's a start.
function peek(Array &$array, &$value){
$value = next($array);
return prev($array);
}
function peek_key(Array &$array, &$key){
next($array);
$key = key($array);
return prev($array);
}
function peek_each(Array &$array, &$key, &$value){
next($array);
list($key, $value) = array(key($array), current($array));
return prev($array);
}
http://www.php.net/next
Note: You won't be able to distinguish the end of an array from a booleanFALSE
element. To properly traverse an array which may containFALSE
elements, see theeach()
function.
while (list($key, $val) = each($fruit)) {
echo "$key => $val\n";
}
each
returns an array or false
. That's very uniquely distinguishable.
Whats wrong with getting a count of number of elements ? And using that to detect if I am on last element ? http://codepad.org/zTRRjLdl
$myArr = $array = array('a', 'b', 0, 'c', null, 'd');
$count = count($myArr);
$index = 0;
foreach($myArr as $value)
{
var_dump($value);
$index++;
if($index == $count)
echo "Its the last one here :)";
}
Well, this is what I ended up going with:
$array = array('alpha', 'b' => 'beta', null, 'g' => 'gamma', false, 0, 'delta', null);
if(!empty($array)){
list($end) = array_keys(array_slice($array, -1, 1, true));
foreach($array as $key => &$value){
// do important stuff on each element
if($key !== $end){
// do important stuff on all but last element
}
}
}
Regardless, feel free to answer if you have a better solution. This works, but I'd gladly accept anything better.
Feeding off of your answer, here is another way of going about this that allows independent testing outside of the actual loop. This test does not affect the internal array pointer.
$arr = array('alpha', 'b' => 'beta', null, 'g' => 'gamma', false, 0, 'delta', null);
if (!empty($arr)) {
while (TRUE) {
// advance and rewind the internal array pointer to do useful things
// (note that this example doesn't cover rewinding the internal array
// pointer too far)
if (array_end($arr)) {
break;
}
}
}
/**
* Detect the end of an array
* @return boolean TRUE if we've reached the end of the array or exceeded its bounds
*/
function array_end(array $arr) {
$currentKey = key($arr);
if (NULL === $currentKey) {
// we've moved beyond the bounds of the array
return TRUE;
}
$lastKey = key(array_slice($arr, -1, 1, TRUE));
return ($currentKey === $lastKey);
}
精彩评论