Sunday 12 November 2017

php - What's the best way to get the last element of an array without deleting it?

itemprop="text">

Ok,




I
know all about rel="noreferrer">array_pop(), but that deletes the
last element. What's the best way to get the last element of an array without deleting
it?



EDIT: Here's a
bonus:



$array = array('a' =>
'a', 'b' => 'b', 'c' =>
'c');


or
even




$array =
array('a', 'b', 'c', 'd');
unset($array[2]);
echo
$array[sizeof($array) - 1]; // Output: PHP Notice: Undefined offset: 2 in - on line
4

itemprop="text">
class="normal">Answer



The many
answers in this thread present us with many different options. To be able to choose from
them I needed to understand their behavior and performance. In this answer I will share
my findings with you, benchmarked against PHP versions 5.6.38,
7.2.10 and 7.3.0RC1 ( href="https://wiki.php.net/todo/php73" rel="noreferrer">expected Dec 13
2018).



The options
(<s) I will test
are:






(functions
mentioned: rel="noreferrer">array_key_last , href="https://secure.php.net/manual/en/function.array-keys.php"
rel="noreferrer">array_keys , href="https://secure.php.net/manual/en/function.array-pop.php"
rel="noreferrer">array_pop , href="https://secure.php.net/manual/en/function.array-slice.php"
rel="noreferrer">array_slice , href="https://secure.php.net/manual/en/function.array-values.php"
rel="noreferrer">array_values , href="https://secure.php.net/manual/en/function.count.php"
rel="noreferrer">count , href="https://secure.php.net/manual/en/function.end.php"
rel="noreferrer">end , href="https://secure.php.net/manual/en/function.reset.php"
rel="noreferrer">reset)



The
test inputs (<>s) to combine
with:




  • null
    = $array =
    null;

  • empty
    = $array =
    [];

  • last_null
    = $array =
    ["a","b","c",null];

  • auto_idx
    = $array =
    ["a","b","c","d"];


  • shuffle
    = $array = []; $array[1] = "a"; $array[2] = "b"; $array[0] =
    "c";

  • 100
    = $array = []; for($i=0;$i<100;$i++) { $array[] = $i;
    }

  • 100000
    = $array = []; for($i=0;$i<100000;$i++) { $array[] = $i;
    }



For
testing I will use the 5.6.38, 7.2.10
and 7.3.0RC1 rel="noreferrer">PHP docker containers
like:



sudo docker run -it --rm
php:5.6.38-cli-stretch php -r '<< HERE>>>'



Each
combination of the above listed <s
and <>s will be run on all versions of
PHP. For each test run the following code snippet is
used:



<>
error_reporting(E_ALL); <


For
each run this will var_dump the last retrieved last value of the test input and print
the average duration of one iteration href="https://en.wikipedia.org/wiki/International_System_of_Units#Prefixes"
rel="noreferrer">in femtoseconds (0.000000000000001th of a
second).



The results are as
follows:



/==========================================================================================================================================================================================================================================================================================================================================================================================================================\

||
|| T E S T I N P U T - 5 . 6 . 3 8 || T E S T I N P U T - 7 . 2 . 1 0 || T E S T I N P U
T - 7 . 3 . 0 R C 1 ||
|| || null | empty | last_null | auto_idx | shuffle |
100 | 100000 || null | empty | last_null | auto_idx | shuffle | 100 | 100000 || null |
empty | last_null | auto_idx | shuffle | 100 | 100000
||
||============================OPTIONS -
ERRORS==========================++===============+===============+===============+===============+===============+===============+===============++===============+===============+===============+===============+===============+===============+===============++===============+===============+===============+===============+===============+===============+===============<|
||
1. $x = array_values(array_slice($array, -1))[0]; || W1 + W2 | N1 | - | - | - | - | - ||
W1 + W2 | N1 | - | - | - | - | - || W1 + W2 | N1 | - | - | - | - | - ||
|| 2.
$x = array_slice($array, -1)[0]; || W1 | N1 | - | - | - | - | - || W1 | N1 | - | - | - |
- | - || W1 | N1 | - | - | - | - | - ||
|| 3. $x =
array_pop((array_slice($array, -1))); || W1 + W3 | - | - | - | - | - | - || W1 + N2 + W3
| N2 | N2 | N2 | N2 | N2 | N2 || W1 + N2 + W3 | N2 | N2 | N2 | N2 | N2 | N2
||
|| 4. $x = array_pop((array_slice($array, -1, 1))); || W1 + W3 | - | - | -
| - | - | - || W1 + N2 + W3 | N2 | N2 | N2 | N2 | N2 | N2 || W1 + N2 + W3 | N2 | N2 | N2
| N2 | N2 | N2 ||
|| 5. $x = end($array); reset($array); || W4 + W5 | - | - |
- | - | - | - || W4 + W5 | N2 | N2 | N2 | N2 | N2 | N2 || W4 + W5 | - | - | - | - | - |
- ||
|| 6. $x = end((array_values($array))); || W2 + W4 | - | - | - | - | - |
- || W2 + N2 + W4 | - | - | - | - | - | - || W2 + N2 + W4 | N2 | N2 | N2 | N2 | N2 | N2
||
|| 7. $x = $array[count($array)-1]; || - | N3 | - | - | - | - | - || W7 |
N3 | - | - | - | - | - || W7 | N3 | - | - | - | - | - ||

|| 8.
$keys = array_keys($array); $x = $array[$keys[count($keys)-1]]; || W6 | N3 + N4 | - | -
| - | - | - || W6 + W7 | N3 + N4 | - | - | - | - | - || W6 + W7 | N3 + N4 | - | - | - |
- | - ||
|| 9. $x = $array[] = array_pop($array); || W3 | - | - | - | - | - |
- || W3 | - | - | - | - | - | - || W3 | - | - | - | - | - | - ||
|| 10. $x =
$array[array_key_last($array)]; || F1 | F1 | F1 | F1 | F1 | F1 | F1 || F2 | F2 | F2 | F2
| F2 | F2 | F2 || W8 | N4 | F2 | F2 | F2 | F2 | F2
||
||========================OPTIONS - VALUE
RETRIEVED=====================++===============+===============+===============+===============+===============+===============+===============++===============+===============+===============+===============+===============+===============+===============++===============+===============+===============+===============+===============+===============+===============<|
||
1. $x = array_values(array_slice($array, -1))[0]; || NULL | NULL | NULL | string(1) "d"
| string(1) "c" | int(99) | int(99999) || NULL | NULL | NULL | string(1) "d" | string(1)
"c" | int(99) | int(99999) || NULL | NULL | NULL | string(1) "d" | string(1) "c" |
int(99) | int(99999) ||
|| 2. $x = array_slice($array, -1)[0]; || NULL | NULL
| NULL | string(1) "d" | string(1) "c" | int(99) | int(99999) || NULL | NULL | NULL |
string(1) "d" | string(1) "c" | int(99) | int(99999) || NULL | NULL | NULL | string(1)
"d" | string(1) "c" | int(99) | int(99999) ||
|| 3. $x =
array_pop((array_slice($array, -1))); || NULL | NULL | NULL | string(1) "d" | string(1)
"c" | int(99) | int(99999) || NULL | NULL | NULL | string(1) "d" | string(1) "c" |
int(99) | int(99999) || NULL | NULL | NULL | string(1) "d" | string(1) "c" | int(99) |
int(99999) ||
|| 4. $x = array_pop((array_slice($array, -1, 1))); || NULL |
NULL | NULL | string(1) "d" | string(1) "c" | int(99) | int(99999) || NULL | NULL | NULL
| string(1) "d" | string(1) "c" | int(99) | int(99999) || NULL | NULL | NULL | string(1)
"d" | string(1) "c" | int(99) | int(99999) ||
|| 5. $x = end($array);
reset($array); || NULL | bool(false) | NULL | string(1) "d" | string(1) "c" | int(99) |
int(99999) || NULL | bool(false) | NULL | string(1) "d" | string(1) "c" | int(99) |
int(99999) || NULL | bool(false) | NULL | string(1) "d" | string(1) "c" | int(99) |
int(99999) ||
|| 6. $x = end((array_values($array))); || NULL | bool(false) |
NULL | string(1) "d" | string(1) "c" | int(99) | int(99999) || NULL | bool(false) | NULL
| string(1) "d" | string(1) "c" | int(99) | int(99999) || NULL | bool(false) | NULL |
string(1) "d" | string(1) "c" | int(99) | int(99999) ||

|| 7. $x =
$array[count($array)-1]; || NULL | NULL | NULL | string(1) "d" | string(1) "b" | int(99)
| int(99999) || NULL | NULL | NULL | string(1) "d" | string(1) "b" | int(99) |
int(99999) || NULL | NULL | NULL | string(1) "d" | string(1) "b" | int(99) | int(99999)
||
|| 8. $keys = array_keys($array); $x = $array[$keys[count($keys)-1]]; ||
NULL | NULL | NULL | string(1) "d" | string(1) "c" | int(99) | int(99999) || NULL | NULL
| NULL | string(1) "d" | string(1) "c" | int(99) | int(99999) || NULL | NULL | NULL |
string(1) "d" | string(1) "c" | int(99) | int(99999) ||
|| 9. $x = $array[] =
array_pop($array); || NULL | NULL | NULL | string(1) "d" | string(1) "c" | int(99) |
int(99999) || NULL | NULL | NULL | string(1) "d" | string(1) "c" | int(99) | int(99999)
|| NULL | NULL | NULL | string(1) "d" | string(1) "c" | int(99) | int(99999)
||
|| 10. $x = $array[array_key_last($array)]; || N/A | N/A | N/A | N/A | N/A
| N/A | N/A || N/A | N/A | N/A | N/A | N/A | N/A | N/A || N/A | N/A | N/A | N/A | N/A |
N/A | N/A ||
||=================OPTIONS - FEMTOSECONDS PER
ITERATION=================++===============+===============+===============+===============+===============+===============+===============++===============+===============+===============+===============+===============+===============+===============++===============+===============+===============+===============+===============+===============+===============<|
||
1. $x = array_values(array_slice($array, -1))[0]; || 803 | 466 | 390 | 384 | 373 | 764 |
1.046.642 || 691 | 252 | 101 | 128 | 93 | 170 | 89.028 || 695 | 235 | 90 | 97 | 95 | 188
| 87.991 ||
|| 2. $x = array_slice($array, -1)[0]; || 414 | 349 | 252 | 248 |
246 | 604 | 1.038.074 || 373 | 249 | 85 | 91 | 90 | 164 | 90.750 || 367 | 224 | 78 | 85
| 80 | 155 | 86.141 ||
|| 3. $x = array_pop((array_slice($array, -1))); || 724
| 228 | 323 | 318 | 350 | 673 | 1.042.263 || 988 | 285 | 309 | 317 | 331 | 401 | 88.363
|| 877 | 266 | 298 | 300 | 326 | 403 | 87.279 ||
|| 4. $x =
array_pop((array_slice($array, -1, 1))); || 734 | 266 | 358 | 356 | 349 | 699 |
1.050.101 || 887 | 288 | 316 | 322 | 314 | 408 | 88.402 || 935 | 268 | 335 | 315 | 313 |
403 | 86.445 ||
|| 5. $x = end($array); reset($array); || 715 | 186 | 185 |
180 | 176 | 185 | 172 || 674 | 73 | 69 | 70 | 66 | 65 | 70 || 693 | 65 | 85 | 74 | 68 |
70 | 69 ||

|| 6. $x = end((array_values($array))); || 877 | 205 |
320 | 337 | 304 | 2.901 | 7.921.860 || 948 | 300 | 336 | 308 | 309 | 509 | 29.696.951 ||
946 | 262 | 301 | 309 | 302 | 499 | 29.234.928 ||
|| 7. $x =
$array[count($array)-1]; || 123 | 300 | 137 | 139 | 143 | 140 | 144 || 312 | 218 | 48 |
53 | 45 | 47 | 51 || 296 | 217 | 46 | 44 | 53 | 53 | 55 ||
|| 8. $keys =
array_keys($array); $x = $array[$keys[count($keys)-1]]; || 494 | 593 | 418 | 435 | 399 |
3.873 | 12.199.450 || 665 | 407 | 103 | 109 | 114 | 431 | 30.053.730 || 647 | 445 | 91 |
95 | 96 | 419 | 30.718.586 ||
|| 9. $x = $array[] = array_pop($array); || 186
| 178 | 175 | 188 | 180 | 181 | 186 || 83 | 78 | 75 | 71 | 74 | 69 | 83 || 71 | 64 | 70
| 64 | 68 | 69 | 81 ||
|| 10. $x = $array[array_key_last($array)]; || N/A |
N/A | N/A | N/A | N/A | N/A | N/A || N/A | N/A | N/A | N/A | N/A | N/A | N/A || 370 |
223 | 49 | 52 | 61 | 57 | 52 ||

\=========================================================================================================================================================================================================================================================================================================================================================================================================================/



The above mentioned
Fatal, Warning and
Notice codes translate
as:




F1 = Fatal error:
Call to undefined function array_key_last() in Command line code on line 1
F2
= Fatal error: Uncaught Error: Call to undefined function array_key_last() in Command
line code:1
W1 = Warning: array_slice() expects parameter 1 to be array, null
given in Command line code on line 1
W2 = Warning: array_values() expects
parameter 1 to be array, null given in Command line code on line 1
W3 =
Warning: array_pop() expects parameter 1 to be array, null given in Command line code on
line 1
W4 = Warning: end() expects parameter 1 to be array, null given in
Command line code on line 1
W5 = Warning: reset() expects parameter 1 to be
array, null given in Command line code on line 1
W6 = Warning: array_keys()
expects parameter 1 to be array, null given in Command line code on line 1
W7
= Warning: count(): Parameter must be an array or an object that implements Countable in
Command line code on line 1
W8 = Warning: array_key_last() expects parameter 1
to be array, null given in Command line code on line 1

N1 = Notice:
Undefined offset: 0 in Command line code on line 1
N2 = Notice: Only variables
should be passed by reference in Command line code on line 1
N3 = Notice:
Undefined offset: -1 in Command line code on line 1
N4 = Notice: Undefined
index: in Command line code on line
1


Based on this output
I draw the following
conclusions:




  • newer
    versions of PHP perform better with the exception of these options that became
    significantly
    slower:



    • option
      .6.
      $x =
      end((array_values($array)));

    • option
      .8.
      $keys = array_keys($array); $x =
      $array[$keys[count($keys)-1]];


  • these
    options scale best for very large
    arrays:


    • option
      .5.
      $x = end($array);
      reset($array);

    • option
      .7.
      $x =
      $array[count($array)-1];


    • option
      .9.
      $x = $array[] =
      array_pop($array);

    • option
      10.
      $x =
      $array[array_key_last($array)];
      (since PHP
      7.3)


  • these options
    should only be used for auto-indexed
    arrays
    :


    • option
      .7.
      $x = $array[count($array)-1];
      (due to use of
      count)

    • option
      .9.
      $x = $array[] =
      array_pop($array);
      (due to assigning value losing original
      key)


  • this option
    does not preserve the array's internal
    pointer




    • option
      .5.
      $x = end($array);
      reset($array);


  • this
    option is an attempt to modify option
    .5.
    to preserve the array's internal pointer (but sadly it
    does not scale well for very large
    arrays)


    • option
      .6.
      $x =
      end((array_values($array)));


  • the
    new array_key_last function seems to have none of the above
    mentioned limitations with the exception of still being an RC at the time of this
    writing (so use the RC or await it's release Dec
    2018):



    • option
      10.
      $x =
      $array[array_key_last($array)];
      (since PHP
      7.3)




A
bit depending on whether href="https://stackoverflow.com/a/41387093/2799887">using the array as stack or as
queue you can make variations on option 9.



No comments:

Post a Comment

php - file_get_contents shows unexpected output while reading a file

I want to output an inline jpg image as a base64 encoded string, however when I do this : $contents = file_get_contents($filename); print &q...