Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

No "Undefined offset" if array is NULL

Tags:

php

I'm not sure this is a bug, so can anyone tell why does not php show a notice if you try to access a key which is not defined of an array that is NULL? Documentation says

Converting NULL to an array results in an empty array.

So accessing a key that is not defined must generate notice.

<?php

$a = NULL;
echo $a['1'];

$a = array();
echo $a['1'];
?>

Prints out ony

Notice: Undefined offset: 1 in /var/www/shared/1.php on line 14

Thank you for your help.


Edit: I take the liberty of adding another example script to the question

<?php
$a = NULL;
var_dump('line '.__LINE__, $a['1']);

$a = array();
var_dump('line '.__LINE__, $a['1']);

which prints

string(6) "line 3"
NULL

Notice: Undefined offset: 1 in [...]/test.php on line 6
string(6) "line 6"
NULL
like image 906
ilantipov Avatar asked Oct 02 '22 07:10

ilantipov


1 Answers

When you dereference a variable as an array (for reading), the virtual machine will internally call zend_fetch_dimension_address_read, which in turn loads the right value into the result variable, depending on the type of variable you're trying to dereference.

In the case of null (and int / float / bool), it will choose this branch:

case IS_NULL:
  result->var.ptr = &EG(uninitialized_zval);
  PZVAL_LOCK(&EG(uninitialized_zval));
  return;

Whereby EG(uninitialized_zval) is basically the null itself; no notices are raised when this happens. As Amal has pointed out, there's a bug report for this behaviour, but not much has been done about it for almost a year.

Documentation says "Converting NULL to an array results in an empty array."

An array dereference doesn't convert something into an array (unless you use [] or use it in a write context). The conversion that the manual speaks of is most likely an array cast:

var_dump((array)null);
// array(0) { }

Update

After digging into the system a little more, I found that this (partially) makes the following construct work:

$list = ['foo', 'bar', 'baz'];
while (list($key, $value) = each($list)) {
    echo "$key: $value\n";
}

When the end of the array is reached, each() returns false and so internally false[0] and false[1] are evaluated before the list() expression itself yields false.

like image 61
Ja͢ck Avatar answered Oct 13 '22 10:10

Ja͢ck