Bug #78635 [Com]: [Arrow function] In combination with a "substr" call it returns empty string
| From: | marandall@php.net | Date: | Fri, 04 Oct 2019 21:31:20 +0000 |
| Subject: | Bug #78635 [Com]: [Arrow function] In combination with a "substr" call it returns empty string | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-223093@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=78635&edit=1
ID: 78635
Comment by: marandall@php.net
Reported by: php-0919 at jan-runte dot de
Summary: [Arrow function] In combination with a "substr" call
it returns empty string
Status: Not a bug
Type: Bug
Package: Scripting Engine problem
Operating System: macOS 10.14.6
PHP Version: 7.4.0RC3
Block user comment: N
Private report: N
New Comment:
substr explicitly checks for if the number of arguments passed is 3.
Your arrow function defines 3 parameters, and explicitly passes them all each time, thus making the
function believe that the length has been set, which it has.
The length is a null that is being cast into an integer, giving you 0, so the function is returning
an empty string, which is what you're asking it for.
From the docs: If length is given and is 0, FALSE or NULL, an empty string will be returned.
mb_substr works differently and it does accept a specific null.
Previous Comments:
------------------------------------------------------------------------
[2019-10-04 21:22:58] daverandom@php.net
Further to the last suggestion above, to retain type safety on the proxy it's also possible to
do this:
$this->substr = fn(string $str, int ...$chunk) => substr($str, ...$chunk);
However, it's also worth noting that simply:
$this->substr = 'substr';
...will probably do the job in that particular case :-)
------------------------------------------------------------------------
[2019-10-04 21:16:04] requinix@php.net
substr() is one of the few functions that alters its behavior based on the number of arguments.
https://github.com/php/php-src/blob/php-7.4.0RC3/ext/standard/string.c#L2388
Note the "argc > 2" checks.
To properly address that in the arrow function you can use a ternary:
$this->substr = fn(string $string, int $start, int $length = null) =>
func_num_args() == 2
? substr($string, $start)
: substr($string, $start, $length);
Or better yet, if you're just proxying substr() then you can ignore the arguments and instead
$this->substr = fn() => substr(...func_get_args());
------------------------------------------------------------------------
[2019-10-04 21:15:40] daverandom@php.net
See also https://3v4l.org/j1qXn
A (not pretty) work around is https://3v4l.org/Wmqru
------------------------------------------------------------------------
[2019-10-04 21:09:05] daverandom@php.net
Thank you for taking the time to write to us, but this is not
a bug. Please double-check the documentation available at
http://www.php.net/manual/ and the instructions on how to
report
a bug at http://bugs.php.net/how-to-report.php
This is not a bug with arrow functions, strictly speaking it's the expected behaviour of
substr().
Your code explicitly passes NULL to the 3rd argument of substr(), which is then cast to int and the
call ends up being interpreted as substr('search phrase', 6, 0) - which then correctly
returns the empty string.
https://3v4l.org/8hKAl
I have to close this as "not a bug", however I would completely agree with you if you said
this is not intuitive behaviour... it is what it is, though, and it's far too late to fix it
now :-/
------------------------------------------------------------------------
[2019-10-04 20:44:20] php-0919 at jan-runte dot de
Description:
------------
Installation:
phpbrew install 7.4.0RC3 +neutral +mbstring
To implement the string functions in a generically manner the arrow function is the way we go.
The test script demonstrate the misbehavior of the arrow function if it uses "substr".
Without the use of arrow function all is fine. By "mb_substr" in the other hand we have no
problems.
It is not related to the reporting bugs:
- Bug #71648: [DE] substr('abc', 3) returns string(0) "" for php7
- Bug #68863: Inconsistent return from substr()
The arrow function has the issue.
Test script:
---------------
<?php {
trait StringFunctionMapper
{
public Closure $substr;
protected ?string $encoding = null;
public function setSingleByte(): void
{
$this->encoding = null;
$this->substr = fn (string $string, int $start, int $length = null) => substr($string,
$start, $length);
}
public function setMultiByte(string $encoding = 'UTF-8'): void
{
$this->encoding = $encoding;
$this->substr = fn (string $string, int $start, int $length = null) => mb_substr($string,
$start, $length, $this->encoding);
}
}
$temp = new class () {
use StringFunctionMapper;
};
$temp->setSingleByte();
var_dump(substr("search phrase", 6), ($temp->substr)("search phrase", 6));
$temp->setMultiByte();
var_dump(mb_substr("search phrase", 6), ($temp->substr)("search phrase",
6));
}
Expected result:
----------------
string(7) " phrase"
string(7) " phrase"
string(7) " phrase"
string(7) " phrase"
Actual result:
--------------
string(7) " phrase"
string(0) ""
string(7) " phrase"
string(7) " phrase"
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=78635&edit=1