Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

str_contains behaviour differs from php8 behaviour #282

Closed
PatrickRose opened this issue Aug 5, 2020 · 12 comments
Closed

str_contains behaviour differs from php8 behaviour #282

PatrickRose opened this issue Aug 5, 2020 · 12 comments

Comments

@PatrickRose
Copy link

It looks like the PHP8 behaviour for str_contains actually silently accepts a null value (casting it to the empty string), whereas the polyfill doesn't. See this comparison on 3v4l, where you can see that the polyfill throws a TypeError but PHP8 doesn't. The same is probably true for the other str methods, but I haven't confirmed it yet.

Happy to send a PR (possibly just easiest to remove the types from the params?)

@IonBazan
Copy link
Contributor

IonBazan commented Aug 5, 2020

@PatrickRose Good catch!
Unfortunately, removing the typehint will not help as strpos([], 'test') produces a warning instead of TypeError. The simplest solution I see is changing the method definition to function str_contains(string $haystack = null, string $needle): bool but that doesn't seem elegant.

@PatrickRose
Copy link
Author

Ah, of course. Forgot about that behaviour!

Looks like it's the same for $needle as well - here's a 3v4l that checks all the methods and both params. str_starts_with / str_ends_with looks like it might be harder to fix, though I think just manually casting inside those methods might be enough to fix?

I think the method definition should be function str_contains(?string $haystack, ?string $needle), which keeps the previous behaviour about making them required but handles the null.

Shall I get a PR together?

@PatrickRose
Copy link
Author

PatrickRose commented Aug 5, 2020

Absolutely no pressure btw, but what's the release schedule for polyfills? We spotted this because we got hit by it, so it'd be great if the fix could be released quickly (but we can easily work around it in our code)

@stof
Copy link
Member

stof commented Aug 5, 2020

Well, for now, nobody submitted a PR with a fix. So there is nothing to release yet.

Releases are done when needed. There is no fixed schedule.

@PatrickRose
Copy link
Author

Thanks @stof - I'll get a PR together now.

PatrickRose added a commit to PatrickRose/polyfill that referenced this issue Aug 5, 2020
The previous version of the polyfills didn't accept null as a value as
either the haystack or the needle because of the string typehint. In
PHP8, these are silently cast to an empty string.

This matches that behaviour, by making the typehints nullable.

Fixes symfony#282
PatrickRose added a commit to PatrickRose/polyfill that referenced this issue Aug 5, 2020
The previous version of the polyfills didn't accept null as a value as
either the haystack or the needle because of the string typehint. In
PHP8, these are silently cast to an empty string.

This matches that behaviour, by making the typehints nullable.

Fixes symfony#282
@nicolas-grekas
Copy link
Member

Isn't this issue a PHP8 one? Shouldn't PHP8 also reject null, since the types are not nullable?

Can you please open a bug report to bugs.php.net?

Simple reproducer:

function my_str_starts_with(string $haystack, string $needle): bool
{
    return true;
}

var_dump(str_starts_with(null, 'abc'));
var_dump(my_str_starts_with(null, 'abc'));

the second call fails but the first succeeds, unless strict more is enabled.

@PatrickRose
Copy link
Author

PatrickRose commented Sep 14, 2020

@stof also raised this in the linked PR. I'm not too familiar with how it works on an internal level, but my guess is that weak mode just casts the args to the relevant type in a way that can't be replicated in userland.

I'm happy to open a bug but it feels like it could possibly be a major BC break since that would need to be applied to all internal functions?

@nicolas-grekas
Copy link
Member

I think it's worth discussing with php-internals yes, please open a bug report there. Userland should be able to polyfill to me...

/cc @nikic in case you have some bandwidth to have a look here.

@PatrickRose
Copy link
Author

@nikic
Copy link
Contributor

nikic commented Sep 14, 2020

Yes, this is an open bug in the way scalar types are treated by internal functions. I expect it will get deprecated in PHP 8.1, once I pick up php/php-src#4227 again.

For the purposes of the polyfill, I would recommend using a normal string type. I don't think it makes sense to be bug-compatible with PHP in this regard.

@PatrickRose
Copy link
Author

It's been closed as a won't fix on the bug tracker and since we have to choose between making it work the same for strict_mode=1 and making it match strict_mode=0 then it probably makes sense to go with the strict_mode=1 version as the library currently does.

@nicolas-grekas
Copy link
Member

Thanks for reporting and investigating!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants