Discrepancy between expected and actual output
From manual page: https://php.net/language.types.string
In Example #18, the expected output described in the documentation is:
string(1) "b"
bool(true)
Warning: Illegal string offset '1.0' in /tmp/t.php on line 7
string(1) "b"
bool(false)
Warning: Illegal string offset 'x' in /tmp/t.php on line 9
string(1) "a"
bool(false)
string(1) "b"
bool(false)
However, the actual output is:
string(1) "b"
bool(true)
Fatal error: Uncaught TypeError: Cannot access offset of type string on string in php-wasm run script:7
Stack trace:
#0 {main}
thrown in php-wasm run script on line 7
The "actual" output that you have provided:
string(1) "b" bool(true) Fatal error: Uncaught TypeError: Cannot access offset of type string on string in php-wasm run script:7 Stack trace: #0 {main} thrown in php-wasm run script on line 7
Clearly indicates that you are running the PHP code in an environment that uses PHP-WASM (PHP compiled to WebAssembly) which has stricter handling of string offsets and might not behave the same way as "regular" PHP.
PHP has been largely used as an interpreted language and when we talk about compiling PHP to WebAssembly, we are referring to compiling the official PHP interpreter, but Wasm is a compilation target and the binary runs on top of a Virtual Machine. This approach opens new opportunities for PHP, as now you can run PHP applications in any environment that has a WebAssembly virtual machine (servers, browsers and mobile phones).
Conclusion on WASM:
PHP-WASM is a lot more strict regarding string offset handling than regular PHP, since it does not allow non-integer or non-numeric values (like '1.0', 'x', '1x') to be used as string indices, resulting in a TypeError. In standard PHP, these cases would either trigger warnings or convert the offsets, but PHP-WASM enforces stricter type constraints, throwing a fatal error when an invalid offset is accessed.
To avoid this error in PHP-WASM, you should ensure that string indices are integers or valid numeric strings ('1', '2', etc.) instead of strings like '1.0' or 'x'.
Official Documentation:
string(1) "b" bool(true)
Warning: Illegal string offset '1.0' in /tmp/t.php on line 7 string(1) "b" bool(false)
Warning: Illegal string offset 'x' in /tmp/t.php on line 9 string(1) "a" bool(false) string(1) "b" bool(false)
Why? Please, do remember that it was written using standard PHP cenarios. When you use non-integer or non-numeric string offsets (such as '1.0' or 'x'), PHP triggers a warning because these are treated as invalid string offsets in PHP versions that enforce stricter checks. In older PHP versions, such offsets might have been cast to integers or handled differently, but in more recent versions (PHP 7 and above), these kinds of warnings are triggered when you try to use a non-integer as a string index. Only warnings, not fatal errors!
Breakdown of the Output:
$str['1'] correctly outputs "b", which is at index 1 of the string 'abc', and isset($str['1']) returns true because the index 1 exists.
$str['1.0'] gets a warning because '1.0' is treated as an invalid string offset in PHP. Normally, PHP would cast it to 1 in older versions, but in newer versions, this results in a warning, and isset($str['1.0']) returns false because '1.0' is not a valid index.
$str['x'] gets a warning here as well because 'x' is not a valid index for a string. PHP tries to access $str['x'], but since this is an invalid index, it returns "a" (the first character in the string), which is what happens when PHP doesn't detect the invalid offset immediately but still tries to perform the access. Also, isset($str['x']) returns false because the index 'x' doesn't exist.
$str['1x'] is not a valid index, and PHP returns "b", which seems like an attempt to access an index that does not exist, so you might get unpredictable results. So, isset($str['1x']) returns false because '1x' is not a valid index.
Conclusion on Official Documentation:
The output shows warnings about illegal string offsets. This happens when trying to access string indices that PHP cannot interpret correctly (such as '1.0' or 'x').
The results for isset() are consistent with PHP’s error handling for such offsets, with false returned for invalid indices.
¤¤¤ The official documentation is 100% correct for standard PHP ¤¤¤
Review:
Can we recapitulate using a very simple sketch? In standard PHP, it results in:
$str = 'abc';
var_dump($str['1']); // string(1) "b" var_dump(isset($str['1'])); // bool(true)
var_dump($str['1.0']); // string(1) "b" var_dump(isset($str['1.0'])); // bool(true)
var_dump($str['x']); // NULL var_dump(isset($str['x'])); // bool(false)
var_dump($str['1x']); // NULL var_dump(isset($str['1x'])); // bool(false)
I apologize for using PHP-WASM in my explanation (I thought it was more direct as it is used in the documentation), but before creating this issue, I tested it with standard PHP to confirm the same results. Specifically, I ran it on PHP 8.3.6 on Ubuntu via WSL and obtained the following output:
/home/user/projects/test.php:4:
string(1) "b"
/home/user/projects/test.php:5:
bool(true)
PHP Fatal error: Uncaught TypeError: Cannot access offset of type string on string in /home/user/projects/test.php:7
Stack trace:
#0 {main}
thrown in /home/user/projects/test.php on line 7
I believe the documentation might need to be updated.
No need to apologise, but despite that we are not "experts" or the official PHP developers, we still believe that nothing has changed since our last comment.
Windows Subsystem for Linux (WSL) is similar to a virtual machine in that it allows you to run Linux on a Windows system, but it works quite differently under the hood and offers distinct advantages compared to traditional virtual machines.
WSL is not a full virtual machine, but it integrates with the Windows kernel to provide a Linux-like environment. WSL shares system resources (like CPU, memory and file system) directly with Windows without the overhead of a hypervisor.
Unlike a traditional VM that needs dedicated resources, WSL allows dynamic resource sharing, making it lighter on system performance. Nonetheless, PHP is still running on top of some kind of a "Virtual Machine".
Can we ask if it WSL 1 or WSL 2 ? The reason why we ask is that: WSL 1 translates Linux system calls into Windows system calls, allowing Linux binaries to run natively and WSL 2 includes a real Linux kernel running in a lightweight virtual machine for full compatibility with Linux applications.
I used WSL 2 (specifically version 2.3.26.0).
Thank you for teaching me many things I didn’t know. However, I just installed PHP 8.4.2 and tested it directly on Windows, and the output was as follows:
string(1) "b"
bool(true)
Fatal error: Uncaught TypeError: Cannot access offset of type string on string in C:\Users\me\test.php:7
Stack trace:
#0 {main}
thrown in C:\Users\me\test.php on line 7
@KERNAMON I understand that you are trying to be helpful, but you are not. The expected output is wrong, and has changes as of PHP 8.0, or even PHP 7.4.
Confusing people that open issues by dumping a novel of stuff that you don't even know about is frankly unhelpful to the reporter, and even to maintainers.
Your whole WASM paragraph is just plain wrong. The WASM PHP runtime is the same C runtime that any normal PHP installation has, be that Windows, Linux, WSL, or whatever.
It frankly feels that you are just using some sort of LLM Gen AI junk to try to "help" but you are doing the opposite.
I am pinging @cmb69 to this issue considering you deemed that you didn't warrant the SPAM classification in https://github.com/php/policies/issues/12, but to me, it does. You have provided multiple comments which are not really useful and don't actually make our (well, at least my) job easier.
If you don't know, do not comment. Especially as I had already tagged this as verified.
@KERNAMON I have marked your conversation as off-topic. I also don't think it's SPAM, but it's definitely very unwelcome. Please do not post any more off-topic discussions and incorrect information.
Is there an official policy for this situation? In the case where expected output changes between PHP versions (like in this case, expected output changed as of PHP 8.0). Add version-specific before-and-after expected output, so two in this case? I'm getting reacquainted with PHP docs after nearly a decade away :)
In any case, it's worth adding a note related to the change under that example to go along with the other notes. A note based on this partial 8.0 migration entry:
"This E_WARNING to TypeError change also affects the E_WARNING "Illegal string offset 'string'" for illegal string offsets."
Well, could have two output sections and use:
https://github.com/php/doc-en/blob/a6621a4baf56fd78a842dfd684f5c981991bddcd/language-snippets.ent#L622
and
https://github.com/php/doc-en/blob/a6621a4baf56fd78a842dfd684f5c981991bddcd/language-snippets.ent#L612
Ah thank you @cmb69, will do, and there sure are a lot of example.outputs.* entities in there to choose from :)