php array access on boolean - php

I recently stumbled across the following:
<? $d=false; var_dump($d[123]); ?>
which yielded NULL, but (unexpected to me) without any notice, as for example
<? $d=array(); var_dump($d[123]); ?>
does produce the well known
Notice: Uninitialized string offset: 123 in - on line 1
What is going on here? Is there any documentation of this behavior?

From here:
Accessing variables of other types (not including arrays or
objects implementing the appropriate interfaces) using [] or {}
silently returns NULL.

I guess that is what you would call undefined behaviour.
It makes sense, as a boolean can not have an offset.
error_reporting(E_ALL);
$d = TRUE;
var_dump($d[0]);
This also produces NULL (if FALSE was coerced to an empty string, it would make sense that TRUE would be 1).
Plus what meze said :)

Quick look at the source code shows that this is expected behavior. But don't ask me why they did it this way...

Related

Why does accessing array index on boolean value does not raise any kind of error?

When I try to access an array by key which is not exists in this array, php will raise "undefined index" notice error. When I try to do the same on strings, "Illegal string offset " warning is raised. This is an expected behavior and I know how to deal with it.
But when I tried this on boolean or integer values nothing happens:
ini_set('display_errors', 1);
error_reporting(E_ALL);
$var = false;
var_dump($var['test']);
I expect to see some error messages, but $var['test'] just silently sets to NULL.
So why does php permit to access boolean value through an array key without any indication that you are doing something wrong?
The hole "access boolean value through an array key" phrase sounds terribly wierd to me, but you can do it in php.
It's sad, but it's documented behaviour.
http://php.net/manual/en/language.types.string.php
Note:
Accessing variables of other types (not including arrays or objects implementing the appropriate interfaces) using [] or {} silently returns NULL.

using array accessor on integer, float or boolean [duplicate]

Edit 2022: This appears to be fixed as of PHP 7.4 which emits a notice.
In PHP, I have error_reporting set to report everything including notices.
Why does the following not throw any notices, errors or anything else?
$myarray = null;
$myvalue = $myarray['banana'];
Troubleshooting steps:
$myarray = array();
$myvalue = $myarray['banana'];
// throws a notice, as expected ✔
$myarray = (array)null;
$myvalue = $myarray['banana'];
// throws a notice, as expected ✔
$myarray = null;
$myvalue = $myarray['banana'];
// no notice or warning thrown, $myvalue is now NULL. ✘ Why?
It's possible it's a bug in PHP, or I'm just not understanding something about how this works.
There are three types which it might be valid to use the array derefence syntax on:
Arrays
Strings (to access the character at the given position)
Object (objects implementing the ArrayAccess interface)
For all other types, PHP just returns the undefined variable.
Array dereference is handled by the FETCH_DIM_R opcode, which uses zend_fetch_dimension_address_read() to fetch the element.
As you can see, there is a special case for NULLs, and a default case, both returning the undefined variable.
Usually, when you try to use a value of one type as if it were another type, either an error or warning gets thrown or "type juggling" takes place. For example, if you try to concatenate two numbers with ., they'll both get coerced to strings and concatenated.
However, as explained on the manual page about type juggling, this isn't the case when treating a non-array like an array:
The behaviour of an automatic conversion to array is currently undefined.
In practice, the behaviour that happens when this "undefined behaviour" is triggered by dereferencing a non-array is that null gets returned, as you've observed. This doesn't just affect nulls - you'll also get null if you try to dereference a number or a resource.
There is an active bug report started at 2006.
And in documentation it is a notice about this in String section.
As of PHP 7.4, this behavior how emits a Notice.
"Trying to access array offset on value of type null"
See the first item in this 7.4 migration page.
https://www.php.net/manual/en/migration74.incompatible.php
This recently struck one of my colleagues in the butt because he neglected to validate the result of a database query before attempting to access column data from the variable.
$results = $this->dbQuery(...)
if($results['columnName'] == 1)
{
// WHEN $results is null, this Notice will be emitted.
}
And I just noticed #Glen's comment, above, citing the relevant RFC.
https://wiki.php.net/rfc/notice-for-non-valid-array-container

Why does PHP not complain when I treat a null value as an array like this?

Edit 2022: This appears to be fixed as of PHP 7.4 which emits a notice.
In PHP, I have error_reporting set to report everything including notices.
Why does the following not throw any notices, errors or anything else?
$myarray = null;
$myvalue = $myarray['banana'];
Troubleshooting steps:
$myarray = array();
$myvalue = $myarray['banana'];
// throws a notice, as expected ✔
$myarray = (array)null;
$myvalue = $myarray['banana'];
// throws a notice, as expected ✔
$myarray = null;
$myvalue = $myarray['banana'];
// no notice or warning thrown, $myvalue is now NULL. ✘ Why?
It's possible it's a bug in PHP, or I'm just not understanding something about how this works.
There are three types which it might be valid to use the array derefence syntax on:
Arrays
Strings (to access the character at the given position)
Object (objects implementing the ArrayAccess interface)
For all other types, PHP just returns the undefined variable.
Array dereference is handled by the FETCH_DIM_R opcode, which uses zend_fetch_dimension_address_read() to fetch the element.
As you can see, there is a special case for NULLs, and a default case, both returning the undefined variable.
Usually, when you try to use a value of one type as if it were another type, either an error or warning gets thrown or "type juggling" takes place. For example, if you try to concatenate two numbers with ., they'll both get coerced to strings and concatenated.
However, as explained on the manual page about type juggling, this isn't the case when treating a non-array like an array:
The behaviour of an automatic conversion to array is currently undefined.
In practice, the behaviour that happens when this "undefined behaviour" is triggered by dereferencing a non-array is that null gets returned, as you've observed. This doesn't just affect nulls - you'll also get null if you try to dereference a number or a resource.
There is an active bug report started at 2006.
And in documentation it is a notice about this in String section.
As of PHP 7.4, this behavior how emits a Notice.
"Trying to access array offset on value of type null"
See the first item in this 7.4 migration page.
https://www.php.net/manual/en/migration74.incompatible.php
This recently struck one of my colleagues in the butt because he neglected to validate the result of a database query before attempting to access column data from the variable.
$results = $this->dbQuery(...)
if($results['columnName'] == 1)
{
// WHEN $results is null, this Notice will be emitted.
}
And I just noticed #Glen's comment, above, citing the relevant RFC.
https://wiki.php.net/rfc/notice-for-non-valid-array-container

Anyone ever used PHP's (unset) casting?

I just noticed PHP has an type casting to (unset), and I'm wondering what it could possibly be used for. It doesn't even really unset the variable, it just casts it to NULL, which means that (unset)$anything should be exactly the same as simply writing NULL.
# Really unsetting the variable results in a notice when accessing it
nadav#shesek:~$ php -r '$foo = 123; unset($foo); echo $foo;'
PHP Notice: Undefined variable: foo in Command line code on line 1
PHP Stack trace:
PHP 1. {main}() Command line code:0
# (unset) just set it to NULL, and it doesn't result in a notice
nadav#shesek:~$ php -r '$foo = 123; $foo=(unset)$foo; echo $foo;'
Anyone ever used it for anything? I can't think of any possible usage for it...
Added:
Main idea of question is:
What is reason to use (unset)$smth instead of just NULL?
As far as I can tell, there's really no point to using
$x = (unset)$y;
over
$x = NULL;
The (unset)$y always evaluates to null, and unlike calling unset($y), the cast doesn't affect $y at all.
The only difference is that using the cast will still generate an "undefined variable" notice if $y is not defined.
There's a PHP bug about a related issue. The bug is actually about a (in my mind) misleading passage elsewhere in the documentation which says:
Casting a variable to null will remove the variable and unset its value.
And that clearly isn't the case.
I’d guess (knowing PHP and it’s notaribly... interesting choices for different things, I may be completely wrong) that it is so that the value does not need setting to a var. For exact reason to use it for a code, I can’t think of an example, but something like this:
$foo = bar((unset) baz());
There you want or need to have null as argument for bar and still needs to call baz() too. Syntax of function has changed and someone did a duck tape fix, like what seems to be hot with PHP.
So I’d say: no reason to use it in well-thought architecture; might be used for solutions that are so obscure that I’d vote against them in first place.
As of PHP 8.0.X, (unset) casting is now removed and cannot be used.
For example it can be used like this
function fallback()
{
// some stuff here
return 'zoo';
}
var_dump(false ? 'foo' : fallback()); // zoo
var_dump(false ? 'foo' : (unset) fallback()); // null
Even if fallback() returns "zoo" (unset) will clear that value.

How strict is undefined index?

I've turned on all error reporting to clean up some undefined indexes, just to make the app I'm making more neat. I've noticed a curious behavior:
Let's say I have the following array: $a = array('test' => false, 'foo' => 'bar')
If I do if ($a['nothere']), I properly get a notice of Undefined index: nothere.
However, if I do if ($a['test']['nothere']), I don't get a notice. At all. Despite nothere definitely not being an index in $a['test'].
Now, if I do $a['test'] = array('baz' => 'poof'), then running if ($a['test']['nothere']) does throw a notice.
Does undefined index checking not check for indexes in an empty array? This is on PHP 5.2.8.
it's because of tricky type juggling.
$a['test'] being cast to [empty] string and then 'nowhere' being cast to 0 and then PHP tries to look for 0's symbol in the empty string. It becomes substring operation, not variable lookup, so, no error raised.
Gee, a man says the same: http://php.net/manual/en/language.types.type-juggling.php
A curious example from my experience:
Being requested via hyperlink index.php?sname=p_edit&page=0, a code
if (isset($_GET['sname'])) { $page['current'] = $_GET['sname'].'.php'; };
echo $page['current'];
produces just one letter "p"
I counted 6 steps and 2 type casts which ends up with such a result.
(Hint: a poor fellow who asked this question had register globals on)

Categories