Bug #63217 [Com]: Constant numeric strings become integers when used as ArrayAccess offset
| From: | a dot schilder at gmx dot de | Date: | Sun, 18 Jun 2017 05:46:05 +0000 |
| Subject: | Bug #63217 [Com]: Constant numeric strings become integers when used as ArrayAccess offset | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-209569@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=63217&edit=1
ID: 63217
Comment by: a dot schilder at gmx dot de
Reported by: kmsheng at pixnet dot tw
Summary: Constant numeric strings become integers when used
as ArrayAccess offset
Status: Analyzed
Type: Bug
Package: Arrays related
Operating System: freebsd
PHP Version: 5.4Git-2012-10-04 (Git)
Block user comment: N
Private report: N
New Comment:
I also ran into this problem and found another strange behavior within it (PHP 7.1.x):
When I use $object["0"], the offset is int(0).
When I use $object[(string)"0"], offset is sometimes string(1) "0", sometimes
int(0), without a recognizable pattern.
Previous Comments:
------------------------------------------------------------------------
[2017-05-26 15:31:10] ajf@php.net
Removing myself from being assigned to this. I could fix it, but I lost interest in doing so for the
most part.
------------------------------------------------------------------------
[2016-04-04 04:20:48] whatchildisthis at gmail dot com
Examples using expressions:
<?php
$test["1" . "0"]; // int(10) expect string(2) "10"
$test[1 + 0 . "0"]; // int(10) expect string(2) "10"
$test[<<<_
10
_
]; // int(10) expect string (2) "10"
$test[(string) "10"]; // only one that worked, string(2) "10"
?>
------------------------------------------------------------------------
[2015-11-24 17:23:15] ajf@php.net
I updated the title to better describe the bug.
------------------------------------------------------------------------
[2015-11-24 15:56:53] ajf@php.net
To clarify why this happens, it wasn't due to wanting to make ArrayAccess like arrays. Rather,
PHP has an optimisation for array indexing with a constant (a literal like "123", 123,
true, false, etc, not the const/define() kind) string (e.g. $_POST["password"]) where it
will check at compile-time if it is numeric and replace it then if so (so $foobar["123"]
becomes $foobar[123], but $foobar["bar"] stays the same). This means we don't have to
run the numeric string check every time that line of code is executed. Arrays in PHP consider
$foo["1"] and $foo[1] to be the same, so otherwise we'd need to check when we run the
code if the string is a number.
The problem is that $foobar in this case might actually be an object with ArrayAccess and not an
array, and so what apparently would be a transparent optimisation ends up causing this bug.
The solution is to remove this optimisation. This won't necessarily cause a performance hit,
because there's other ways we could avoid doing the numeric string check at runtime.
------------------------------------------------------------------------
[2015-11-24 15:10:48] levim@php.net
Changing this back to a bug status. Here is an example where I hope it is clear it is a bug (on
3v4l: https://3v4l.org/XGtVh):
<?php
class Dictionary implements ArrayAccess {
function offsetExists($offset) {}
function offsetGet($offset) {}
function offsetUnset($offset) {}
function offsetSet($offset, $value) {
if (!is_string($offset)) {
throw new InvalidArgumentException();
}
}
}
try {
$Dictionary = new Dictionary();
$Dictionary["12"] = 0xDEADBEEF;
echo "No Exception for \"12\"\n";
} catch (InvalidArgumentException $e) {
echo "Caught Exception for \"12\"\n";
}
try {
$str = "12";
$Dictionary[$str] = 0xDEADBEEF;
echo "No Exception for \$variable = \"12\"\n";
} catch (InvalidArgumentException $e) {
echo "Caught Exception for \$variable = \"12\"\n";
}
?>
------------------------------------------------------------------------
The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
https://bugs.php.net/bug.php?id=63217
--
Edit this bug report at https://bugs.php.net/bug.php?id=63217&edit=1