8

This is just a simple question out of curiosity. I spent the whole day debugging my PHP code, and found the problem was due to treating an integer as an array:

$x = $int[$index]; // this returns null, but no error at all

The integer was actually meant to be an array, but the function that was meant to pass the array messed up and passed the first value in the array instead. Is there any reason why an error isn't shown? Accessing an undefined index on an array creates an error, however trying to access a non-existent index on an integer doesn't?

  • Good question -- it still does this in PHP 7. – Barmar Feb 14 '18 at 19:36
  • Incidentally, same behavior if `$int` is a boolean or a float or null. – Don't Panic Feb 14 '18 at 19:37
  • in PHP 7.1 the $x is NULL – Simonluca Landi Feb 14 '18 at 19:39
  • @SimonlucaLandi That's what the question says. – Barmar Feb 14 '18 at 19:40
  • @Barmar: yes, and also in 7.1 – Simonluca Landi Feb 14 '18 at 19:43
  • That's what I said, it still happens in 7.x. – Barmar Feb 14 '18 at 19:45
  • Funny thing, `$int` can be 5 and `$index` a million, this still var_dumps as NULL without so much as a warning. Whereas `$int = [5];` or `$int = "5";` would throw an undefined index/ uninitialized string offset warning ... so I guess we can't be dealing with _actual_ conversion to a string or array here (and for the latter of course we'd have to define what that should even look like first.) – CBroe Feb 14 '18 at 20:16
  • Same behavior with `bool` and `float` :-( – AbraCadaver Feb 14 '18 at 20:20
  • 2
    Bet you a beer this is a case of an almost endless discussion between the PHP core developers about what error level this should constitute, and what message to return, that eventually ended with just _"ah, eff it, we'll just return NULL then ..."_ :-) – CBroe Feb 14 '18 at 20:29

3 Answers3

3

I originally thought; it typecasts $int to a string because [] is another way of accessing string positions. Seems plausible that that wouldn't generate an error:

$string 'Hello';
echo $string[0]; // H

However, that's not the case:

$int = 1;
echo $int[0];

Outputs nothing and var_dump($int[0]) returns NULL.

Interestingly, the same behavior is exhibited for bool and float and the operation used is FETCH_DIM_R which is Fetch the value of the element at "index" in "array-value" to store it in "result".

From the manual Arrays:

Note: Array dereferencing a scalar value which is not a string silently yields NULL, i.e. without issuing an error message.

Similar to this phenomenon, where no error is generated. Bugs #68110 and #54556:

$array['a'] = null;
echo $array['a']['non-existent'];

Not surprising that assigning doesn't work:

$int = 1;
$int[0] = 2;

Warning: Cannot use a scalar value as an array

So PHP is actually attempting to access the int, bool, float as an array but not generating an error. This is from at least version 4.3.0 to 7.2.2.

AbraCadaver
  • 78,200
  • 7
  • 66
  • 87
  • 1
    Now that you found the documentation, I was able to search for a previous question that quoted the same line. – Barmar Feb 14 '18 at 22:03
1

Contrary to my original theory that you're invoking undefined behavior, this behavior actually is defined in the Array documentation.

Note:
Array dereferencing a scalar value which is not a string silently yields NULL, i.e. without issuing an error message.

In that case, it seems like there's no type juggling happening at all, so these references to documentation regarding conversion to array aren't useful in understanding this.


Explicit conversion to array is defined.

For any of the types integer, float, string, boolean and resource, converting a value to an array results in an array with a single element with index zero and the value of the scalar which was converted. In other words, (array)$scalarValue is exactly the same as array($scalarValue).

Automatic conversion to array is undefined according to the type juggling documenation.

Note:
The behaviour of an automatic conversion to array is currently undefined.

At first I thought this was what was happening in this case, but since salathe pointed out that this behavior is documented elsewhere, I'm not sure what "automatic conversion to array" is.

As to why this gives you a null value without throwing an error, warning, or notice, that's just how the PHP interpreter was implemented, and as far as why that is the case, it's not really answerable here. You'd have to ask the developers, and they might be able to tell you.

Don't Panic
  • 41,125
  • 10
  • 61
  • 80
  • 1
    Also, *"Note: Array dereferencing a scalar value which is not a string silently yields NULL, i.e. without issuing an error message."* from [Arrays](http://php.net/manual/en/language.types.array.php). – salathe Feb 14 '18 at 21:15
  • @salathe Ah, I missed that. I'm wrong then, this behavior _is_ defined. But considering that, what _would_ automatic conversion to array look like? I can't think how you'd cause that if not like this. – Don't Panic Feb 14 '18 at 21:18
  • Maybe it's something like `array_map(func, "string")`, since `array_map()` requires the second argument to be an array. – Barmar Feb 14 '18 at 22:00
  • Oh, good point, @Barmar. That makes sense. – Don't Panic Feb 14 '18 at 22:06
-2

this is "type juggling", a "feature" of PHP.

you can read more in the official doc

EDIT According to documentation, "The behaviour of an automatic conversion to array is currently undefined."

I run a quick test, just for curiosity:

<?php
$int = 1;
$index = 0; 
$x = $int[$index]; 
echo gettype($int[$index]) . PHP_EOL; 
var_dump($x);

and the output shows that gettype() returns NULL, so I guess that, in this case, is converted to NULL

Simonluca Landi
  • 931
  • 8
  • 21
  • 1
    So what type is it being converted to? It's not being converted to a string, because then it would be treated as `substr()`. – Barmar Feb 14 '18 at 19:38
  • 1
    We already knew that `$int[$index]` returns NULL. The question is: what type is `$int` being converted to that allows it to be indexed in the first place? It's not being converted to an array, because `(array)$int` returns `[1]`. – Barmar Feb 14 '18 at 20:47