1

The triple equal I think everyone understands; my doubts are about the double equal. Please read the code below.

<?php
//function to improve readability
function compare($a,$b,$rep)
{
    if($a == $b)
        echo "$rep is true<br>";
    else
        echo "$rep is false<br>";
}

echo "this makes sense to me<br>";
compare(NULL,0,'NULL==0');
compare(NULL,"",'NULL==""');
compare(NULL,[],'NULL==[]');
compare(0,"",'0==""');

echo "now this is what I don't understand<br>";
compare("",[],'""==[]');
compare(0,[],'0==[]');
compare(0,"foo",'0=="foo"');

echo "if I cast to boolean then it makes sense again<br>";
compare("",(bool)[],'""==(bool)[]');
compare(0,(bool)[],'0==(bool)[]');
?>

Output:

this makes sense to me

NULL==0 is true
NULL=="" is true
NULL==[] is true
0=="" is true

now this is what I don't understand

""==[] is false
0==[] is false
0=="foo" is true

if I cast to boolean then it makes sense again

""==(bool)[] is true
0==(bool)[] is true

I would expect an empty array to be "equal" to an empty string or to the integer 0. And I wouldn't expect that the integer 0 would be "equal" to the string "foo". To be honest, I am not really understanding what PHP is doing behind the scenes. Can someone please explain to me what is going on here?

halfer
  • 19,824
  • 17
  • 99
  • 186
2Noob2Good
  • 159
  • 1
  • 12
  • 2
    Don't try to *understand* PHP, just resign yourself to learning/referencing the arbitrary tables of rules: http://php.net/manual/en/types.comparisons.php. – Oliver Charlesworth Nov 08 '15 at 19:44
  • duplicate: http://stackoverflow.com/questions/80646/how-do-the-php-equality-double-equals-and-identity-triple-equals-comp – i am me Nov 08 '15 at 19:44
  • @3.14: see my comment above - I think the question is about how the loose typing rules apply to arrays. I can't see that your suggested dup deals with that issue. – halfer Nov 08 '15 at 19:54
  • @OliverCharlesworth Thanks for the link. It is very usefull. I don't understand so many negative votes though for trying to understand why ""==[] is false 0==[] is false 0=="foo" is true. Maybe I explained something wrong or the title could be better... – 2Noob2Good Nov 08 '15 at 19:57
  • Possible duplicate of [Is the == operator transitive in PHP?](http://stackoverflow.com/questions/4753759/is-the-operator-transitive-in-php) – Oliver Charlesworth Nov 08 '15 at 19:59
  • @2Noob2Good: don't worry about the votes, they were probably just because people thought it has been asked before (I don't think it has, hence my upvote). – halfer Nov 08 '15 at 20:12
  • @2Noob2Good: I might wager that you won't get quick answers on this one, since it's a tricky subject! If there are not better answers in two days, ping me with `@halfer` and I will add a bounty on it. – halfer Nov 08 '15 at 20:35
  • @halfer - What kind of answers are you anticipating, beyond the duplicate I suggested? – Oliver Charlesworth Nov 08 '15 at 20:41
  • Hi @Oliver. Just read your suggested dup just now, and I can't see that it explicitly deals with why an empty array and an empty string are not equal when tested with `==`. User Nacht touched on this case in his/her answer, but other than "it depends what you mean by equality", there is not much of an explanation. The kind of answer I would expect might touch briefly upon PHP internals i.e. what did the PHP core devs intend with their implementation? – halfer Nov 08 '15 at 21:07
  • @halfer: But there are dozens of possible questions that fit the pattern of this one, all answerable with "== isn't transitive" and a link to that docs page, all essentially duplicates. I doubt anyone can authoritatively answer on what the *intended* behaviour was... – Oliver Charlesworth Nov 08 '15 at 21:12
  • @Oliver, I would expect a PHP core developer, or someone familiar with the C code, would be able to answer this. I am not sure transitivity is the issue here, in any case: I think it is to do with the internal casting rules where an array is involved. My view remains that this question is different enough to remain open, but if the community closes it with five votes, so be it `:-)`. – halfer Nov 08 '15 at 21:17
  • @halfer: Have fun following the implementation: https://github.com/php/php-src/blob/master/Zend/zend_operators.c#L1780 ... – Oliver Charlesworth Nov 08 '15 at 21:28
  • Great @Oliver, there's the beginnings of another answer there! – halfer Nov 08 '15 at 21:30
  • @OliverCharlesworth but do you believe it's something hardcoded? No reason behind? I understand it isn't a simple cast of one type to another as I was expecting... There is a more complex logic here or maybe something really hardcoded?... – 2Noob2Good Nov 08 '15 at 22:09
  • I think it makes sense that it is false. From an intuitive perspective. [] is a reference to an array. Arrays have information conatined such as depth, that makes it very different from string type or int. Even if it dosnt contain information, it has information that it is 0 levels deep, etc. Also, "" Is a string reference of sorts, even if it equals to bool value when compared. Since it is empty. But it is not an array. – Björn3 Nov 08 '15 at 22:22
  • @Oliver, Agree the question "why, given apparent inconsistency, is this so?" with emphasis on "why", is a good one. Knowing why makes it easier to deal with. The source is a long ugly list of combinations but without obvious uniform structure. Somewhere in the long history of php there might (or might not) be a very good reason for this. If this reason cannot be uncovered is the correct answer then "This question cannot currently be answered as either no-one can remember or it just evolved that way, but to try to revisit it now would break too much existing code"? Is that a valid SO answer? –  Nov 08 '15 at 22:50
  • @Berniev: we try here to make titles fairly specific, so people can grasp what a question is about before clicking on it. Also, we have an unwritten rule that if someone makes a deliberate edit, someone does not undo it without consultation. I have therefore rolled back the title edit here. If you strongly prefer your own, would you flag the question for a moderator? They can then resolve it as they would an edit disagreement. Thanks! – halfer Nov 16 '15 at 18:26
  • @halfer: Perhaps you missed that the original question was about -three- cases, one of which did not involve arrays. Your original edit of the title ,and indeed your answer seem to miss that. **Pls reconsider** as the usefulness of the question and answer is broader than arrays. BTW my change was vetted and approved. I didn't (don't?) have enough rep to do it on my own. –  Nov 16 '15 at 23:58
  • @Berniev: the quality of reviews varies quite wildly here - search for "robo reviewers" over at _Meta_. – halfer Nov 17 '15 at 08:00
  • @Berniev: anyway, I appreciate your feedback. I had not missed that one of the items was not an array, no - I didn't think it was a central part of the question (if you see the last code block, that item was not dealt with again). Nevertheless I have made an edit to try to merge in the theme of your edit - is that better? (I want to distinguish this question from the many other type-juggling questions - this has been closed as dup once, and I think it is worth differentiating). – halfer Nov 17 '15 at 08:07

2 Answers2

2

The simple answer is that this is the way php has been designed to work.

The outcomes are well defined in the docs comparison operators and comparison tables.

A == comparison between an array (your first two queries) and a string always results in false.

In a == comparison between a number and a string (your third query) the string is converted to a number and then a numeric comparison made. In the case of 0=='foo' the string 'foo' evaluates numerically to 0 and the test becomes 0==0 and returns true. If the string had been 'numeric' e.g. "3" then the result in your case would be false (0 not equal to 3).

Whether the design is "correct" (whatever that may mean) is arguable. It is certainly not always immediately obvious. An illustrative example of the potential fury of the debate can be found in Bug#54547 where the devs argue strongly that the design is rooted in php's history as a web language where everything is a string and should be left alone, and others argue php "violates the principle of least surprise".

To avoid uncertainty use === wherever possible, with the added benefit of potentially showing up assumptions in your code that may not be valid.

  • Reading that bug report, I seems to me there was a chance the change could have been made, but that there was an aggressive crowd willing to abuse the core devs, it was decided to close. If nothing else, it demonstrates how not to support a bug report `;-)`. – halfer Nov 09 '15 at 09:02
1

As someone has already said, the PHP automatic casting rules can be quite tricky, and it is worth using === unless you know both sides will be of the same type. However I believe I can explain this one:

""==[] (returns false)

The initial string "" indicates the comparison will be a string one, and thus [] is cast to a string. When that happens, the right hand side of the comparison will be set to the word Array. You are therefore doing this comparison:

"" == "Array" (returns false)

and thus false is the correct result.

Edit: a helpful comment below casts doubt on my answer via this live code example. I should be interested to see what other answers are supplied.

halfer
  • 19,824
  • 17
  • 99
  • 186
  • Yes I also tried that. And in fact this is exactly my question. If I can't understand how == works I can't use it with my mind 100% at ease. Of course I could always use the === but sometimes the == is really handy. If I could predict the result without looking at a table of course... – 2Noob2Good Nov 08 '15 at 20:09
  • That's a good test @Oliver, and I don't have a ready answer for it. `0==[]` has me stumped too. I wonder if there is some semi-type checking going on here, for the case where one side is an array. – halfer Nov 08 '15 at 20:10
  • @2Noob2Good: yes, as per my answer, use `===` (or do explicit casting) unless you know both sides will always be of the same type. – halfer Nov 08 '15 at 20:11
  • What's happening is that there will be some hard-coded rules under-the-hood. The PHP authors added them thinking that they would make things simpler, but have actually made the semantics *more complex*... – Oliver Charlesworth Nov 08 '15 at 20:11
  • 1
    There is a handy chart [here](http://php.net/manual/en/types.comparisons.php). I don't expect these rules are going to change any time soon. Loose typing can be a blessing ... and a curse. –  Nov 08 '15 at 21:50
  • @Berniev: thanks, very interesting. What I think we need is an explanation as to why certain combinations of type juggling have the result they do. My view is that, whilst people should not do this comparison without explicit casting, an empty string and an empty array should be essentially equal if type is ignored (they both cast to boolean false). However this is not what happens, so I'd be interested in what _is_ happening. – halfer Nov 08 '15 at 22:15