News for hackers. Stuff that matters.
Re:PHP 8 by sleavey on Thursday November 26, 2020 @10:50AM (#25220992)
> 0 == 'foobar' // true

That's PHP7 behaviour that's updated in 8 to return false. I'm not a PHP basher, I really like it these days, but why the heck was that example ever evaluating to true?

Re:PHP 8 by stevekemp on Thursday November 26, 2020 @10:53AM (#25221030)
'foobar' is coerced into a number, which fails for the obvious reason. So it becomes 0, which means the expression is "0 == 0".

Terrible, terrible, behaviour but there are lots of similar examples in PHP because it evolved over time rather than being designed as-is. Some of these things are being fixed over time, like this very example, others can't/won't be.

Re:PHP 8 by Zancarius on Thursday November 26, 2020 @12:50PM (#25222111)
> Terrible, terrible, behaviour but there are lots of similar examples in PHP

So true.

One I ran into recently was comparing hashes that start with '0e' and contain only a numeric component after that prefix. Failure to use the identity operator means that you can have two different hashes returning... equality. PHP apparently thought it a good idea to coerce that into 0 raised to an exponent, which of course always yields zero. e.g.:

    php > var_dump('0e41235843934' == '0e61193475532');
    bool(true)
Yeah, I know: The correct (and only) way to write this is to use the identity operator (===) but it's not at all intuitive. For those of us who are used to this it's fine since it's a force of habit, but for those who aren't it'll lead to unexpected behaviors. The only saving grace is that the quality of PHP code out there has been slowly (slowly!) improving over time, thanks in part to composer and ecosystem/cultural changes.

But it's also not outside the realm of possibility that someone won't eventually forget to add an extra '=' and induce a very difficult bug to isolate...

Re:PHP 8 by jontro on Thursday November 26, 2020 @03:46PM (#25223408)
Is this fixed in php 8? I did not think this was possible as there is no type coercion and not well documented. [1][2]

Noticed "0.2" == "0.20" as another example

[1] https://www.php.net/manual/en/language.operators.comparison.... [2] https://www.php.net/manual/en/language.types.type-juggling.p...

Re:PHP 8 by Zancarius on Thursday November 26, 2020 @04:18PM (#25223597)
> Is this fixed in php 8?

I don't know. It's one of those cases where fixing it to do the "right" thing would potentially break a lot of software depending on this sort of erroneous behavior. Part of me wants to say "I hope so" and part of me is kinda terrified at what might happen if they did. Shouldn't be difficult to fix, but it would definitely take some time.

Someone should know if there's a decent linter that would pick this up to make it easier to fix, I would imagine!

> I did not think this was possible as there is no type coercion and not well documented.

I think when applying the equality operator (==) in lieu of the identity operator (===) between strings PHP uses heuristics to decide what to do. If it looks like a number, it coerces it into an int or a float. As an example:

    php > var_dump('1e12' == 1e12);
    bool(true)
As ridiculous as I think it is, I also take the approach that it's just what PHP does. Weird, maybe a bit eccentric, probably a contributor to difficult-to-find bugs, but it's just something we have to keep in mind. Perhaps I'm feeling charitable because it's Thanksgiving!
Re:PHP 8 by spdionis on Friday November 27, 2020 @07:29AM (#25228150)
It is well documented that strings are converted to integers when comparing with integers.

It is well documented that when converted to integers, strings containing a number at the start will be converted to that number, and drop any string after, e.g. '1eabc' becomes 1.

It's also been a best practice for a looong time (since something like PHP 5.4) to use === to test for equality.

Re:PHP 8 by Zancarius on Saturday November 28, 2020 @05:10PM (#25240980)
> It is well documented [...]

Yes, it's documented, but it doesn't make it any less obnoxious. IMO the thought of implicit conversion is absolutely asinine.

But, in fairness, PHP isn't the only language that does this. Python, at least, is more sane.

> and drop any string after, e.g. '1eabc' becomes 1.

In defense of PHP, it does yield a NOTICE if you attempt to apply certain operations to implicitly cast strings (e.g. addition), so there's that.

Suffices to say that while I've written PHP for years, I'm quite comfortable with its idiosyncrasies, it doesn't mean I don't find them appallingly brain damaged. :)

FWIW the identity operator (===) is also a best practice in JS for nearly identical reasons which also exhibits similar (and in some cases nearly identical) implicit casting.

Re:PHP 8 by spdionis on Saturday November 28, 2020 @06:56PM (#25241669)
Yes, implicit conversion in both PHP and JS are brain damaged by today standards, but that's life with legacy cruft.
Re:PHP 8 by Zancarius on Wednesday December 02, 2020 @04:21PM (#25281822)
> but that's life with legacy cruft.

So true.

I can't really complain. Well, I can, and that's what I've been doing in much of this thread.

It's mostly just yelling at the sky for no good reason other than to make myself feel better at this point, if I were to be completely honest with you.

Re:PHP 8 by jontro on Sunday November 29, 2020 @09:05AM (#25245156)
Still in js "0.2" == "0.20" would always be false. My instinct would be that comparing two different strings would be false in php too.

The problem for me is working with a big legacy codebase. I'd rather have php break backwards compatibility and change === to ==.

Re:PHP 8 by Zancarius on Wednesday December 02, 2020 @04:27PM (#25281869)
> Still in js "0.2" == "0.20" would always be false. My instinct would be that comparing two different strings would be false in php too.

Nope.

I wish I were kidding. This is where PHP diverges from JS in a way that really will surprise people coming from JS (PHP7.something):

    php > var_dump("0.2" == "0.20");
    bool(true)
> I'd rather have php break backwards compatibility and change === to ==.

I have mixed feelings on this.

On the one hand, I desperately want to agree with you, and probably for all the same reasons. On the other hand, languages like PHP with their dynamic typing system make implicit conversion almost a necessity to retain the identity operator (===) because they strive not to break "too much" (for some value of "too much").

Although, I'd imagine your argument is akin to "well, just cast it to what you expect" (e.g. `(int)$_GET['value']`), and you're right. That's how it should be done, of course.

But, as you mentioned about legacy code bases... sometimes it's not that easy.

Re:PHP 8 by sleavey on Thursday November 26, 2020 @10:56AM (#25221061)
I see. This change prompts me as something that could break a lot of code running on web servers where the sysadmin updates to PHP8 assuming it will be backwards compatible. I wonder if they did any code searching to see how widely used such expressions are in the wild.
Re:PHP 8 by bavell on Thursday November 26, 2020 @11:03AM (#25221124)
I don't think anyone reading the migration guide [0] is going to assume their app/lib is backwards compatible without some effort.

[0] https://www.php.net/manual/en/migration80.php

Re:PHP 8 by rovr138 on Friday November 27, 2020 @08:48AM (#25228670)
And anyone that knows the basics about semver
Re:PHP 8 by scaladev on Thursday November 26, 2020 @11:01AM (#25221099)
And people say C++ is a complicated language.
Re:PHP 8 by will4274 on Thursday November 26, 2020 @03:13PM (#25223189)
Yes because ('0' == 32) returning true makes more intuitive sense. There are languages without type coercion for comparisons (e.g. OCaml), but C++ isn't one of them.
Re:PHP 8 by daneel_w on Thursday November 26, 2020 @11:14AM (#25221206)
In the absence of strict type checking it would be terrible, but == performs a loose comparison, and "foobar" cannot cast to any other number than 0. Perl will go about it the exact same way. Contrast this against strict comparison, "0" === 0, which will evaluate as false.
Re:PHP 8 by xeeeeeeeeeeenu on Thursday November 26, 2020 @11:47AM (#25221503)
>Perl will go about it the exact same way.

No, Perl is completely different and IMO it's the only mainstream dynamically typed language that has sane comparison operators.

Perl has two sets of operators, numeric (==, +, *, <, >, <=> etc.) and stringwise (eq, ., lt, gt, cmp etc.). You can think of them as explicit (but concise) casts. For example, Perl's $foo eq $bar is roughly equivalent to Python's str(foo) == str(bar).

It is true that "foobar" == 0 returns true in Perl but, as I showed above, it does that for a completely different reason.

Re:PHP 8 by hypertele-Xii on Thursday November 26, 2020 @11:18AM (#25221239)
Maybe "foobar" should evaluate to NaN.
Re:PHP 8 by _-___________-_ on Thursday November 26, 2020 @11:31AM (#25221347)
Does PHP have separate int and float types? NaN is a float value and I would expect 0 to be an int.
Re:PHP 8 by ragnese on Thursday November 26, 2020 @11:52AM (#25221564)
It does
Re:PHP 8 by lgessler on Thursday November 26, 2020 @11:10AM (#25221177)
I'm kind of surprised they'd change a core language semantic, even in a major update... won't this make upgrading to PHP8 for a large codebase hard to do with confidence?
Re:PHP 8 by nikic on Thursday November 26, 2020 @11:32AM (#25221363)
That was certainly a concern. When instrumenting PHP to detect where the behavior changes and testing various codebases, I found that this actually happens much more rarely than I would have anticipated in advance. We're talking like 2 occurrences in the test suite of major frameworks.
Re:PHP 8 by chrisandchris on Thursday November 26, 2020 @12:48PM (#25222096)
Strict types (scalar type hints for method signatures) have been around since PHP 7, and since then I would say it is recommended to always use === (with type check) over == (no type check) so one would have enough time to upgrade it‘s code.

And it also just makes sense from the language design perspective to fix that behaviour. Having a major version coming is a good time to fix such stuff imho.

Re:PHP 8 by stephenr on Thursday November 26, 2020 @01:57PM (#25222671)
Strict comparison operators have been considered best practice since well before 7.0
Re:PHP 8 by DJBunnies on Thursday November 26, 2020 @10:56AM (#25221062)
== is loose type.

=== is strict.

Re:PHP 8 by tonyedgecombe on Thursday November 26, 2020 @11:31AM (#25221345)
Is there any way to force the use of ===
Re:PHP 8 by stephenr on Thursday November 26, 2020 @01:59PM (#25222678)
Write `===` when you want to compare things.

There is no way to disable the `==` operator or make it do strict comparisons (yet)

Re:PHP 8 by DJBunnies on Thursday November 26, 2020 @11:53AM (#25221575)

    declare(scrict_types=1);
Re:PHP 8 by stephenr on Thursday November 26, 2020 @01:59PM (#25222681)
That isn’t what that does.
Re:PHP 8 by dkarlovi on Thursday November 26, 2020 @02:08PM (#25222749)
Enforce by code style tools.
Re:PHP 8 by nkuttler on Thursday November 26, 2020 @10:52AM (#25221020)
Just a guess, but casting a string that's not a number to int would give you zero?
Re:PHP 8 by belst on Thursday November 26, 2020 @10:52AM (#25221015)
because (int)'foobar' is 0
Re:PHP 8 by acomjean on Thursday November 26, 2020 @10:58AM (#25221078)
JavaScript and php have the === which doesn’t try casting types.

Php has good documentation with examples which I appreciate :

https://www.php.net/manual/en/language.operators.comparison....

Re:PHP 8 by tyingq on Thursday November 26, 2020 @10:55AM (#25221058)
I suspect they copied that behavior from Perl.
Re:PHP 8 by xorcist on Thursday November 26, 2020 @04:42PM (#25223734)
Perl avoids this problem by having contexts, a bit like casts but with easier syntax, and by having separate numeric and string equality operators.
Re:PHP 8 by tyingq on Thursday November 26, 2020 @05:18PM (#25223925)
Is there a reason returning undefined instead of true in those cases (string doesn't look like a number) would be worse?
Re:PHP 8 by xorcist on Saturday November 28, 2020 @06:22AM (#25236956)
Very few functions in Perl does that. It will emit a warning instead.

As to why that is, perhaps someone with more Perl knowledge can chime in. I suspect it has to do with undef being inconvenient for signalling failure, since its evaluation will be context dependent (an array of undef is true but a numeric undef is false).

Type conversion is built into the language at a fundamental level. Languages that borrows the syntax but not the type model can be confusing in cases, but Perl is pretty consistent once you get the basics.