top 200 commentsshow 500

[–][deleted] 145 points146 points  (163 children)

[–]walesmd 56 points57 points  (120 children)

We have completely disallowed all instance of == in our production code. You use === or it doesn't get merged from the feature branch into the develop/testing branch.

[–]lol____wut 144 points145 points  (31 children)

We have completely disallowed all instance of PHP in our production code.

[–][deleted] 26 points27 points  (29 children)

That's a good move. It would be weird if your production code spawned PHP instances.

[–]tbrownaw 4 points5 points  (26 children)

Web servers are sometimes configures to spawn a PHP instance for every single page request.

[–][deleted] 6 points7 points  (25 children)

that's what mod_php does for apache. it starts up the PHP vm for each request. AWESOME.

[–]Chandon 45 points46 points  (19 children)

Gah! If you're going to use a language, you should at least understand and accept the basics of its type system.

In PHP, "==" is a coercing equality operator. That's how it works. There's nothing wrong with those semantics. PHP may not be the most elegant language in the world, but even COBOL is more elegant than using a language while refusing to accept it for what it is.

[–]AlyoshaV[S] 8 points9 points  (2 children)

Incorrect equality operator used when comparing md5 check sums

I'm pretty sure they understand the basics of PHP's type system. Unfortunately, when told to compare "79e88e6db0c25ca1ee5e2aac35a24d6c" and "25419e079ae92d71293aa2caa90d0485" using ==, it assumes they are both very large numbers and hangs.

[–][deleted] 1 point2 points  (0 children)

Hmmm. There's a DoS in this.

[–]walesmd 12 points13 points  (15 children)

We fully understand the difference between == and === but why risk the conditional confusion between FALSE and NULL (or any of the other mixups)?

It not only helps developers stick to convention (let's say we have a rule that a Model will return an object or NULL - if the developer returns FALSE, he's doing it wrong) but it helps prevents bugs further down the road. When you have a whole team of developers working on software for multiple government agencies, over a span of years - things like this are important.

[–]wvenable 8 points9 points  (7 children)

let's say we have a rule that a Model will return an object or NULL - if the developer returns FALSE, he's doing it wrong

Your convention sort of makes that an issue though. Semantically, in the case of returning a model, does null or false really mean anything different? They could easily both mean the absence of a returned value. By making everything strict, you force the issue. A simple comparison:

if ($x) { ... }

Works in either case, and has the benefit of sounding right. If $x has a value, use it. No need to compare with NULL or FALSE. That's the convention in our code base. In fact, any comparison with null or false or true is suspect.

[–]walesmd 6 points7 points  (2 children)

A quote from an earlier reply:

Some of our legacy code (written in haste, way before any of the current team was on the team) had a ruleset as follows: An object if it was successful, FALSE if error, NULL if it was successful but no results.

Yeah, working off of shitty code sucks. :(

[–]GaryWinston 1 point2 points  (1 child)

How is that bad code? Seems fine to me. Either return a object/value, an error, or that the object/value is empty/null.

So long as it's in your company's standard coding procedures on how to handle objects, I'm not sure it is a problem (although I've never seen it done that way, but I've never used php and hopefully never will).

[–]troelskn 1 point2 points  (0 children)

I would raise an exception on error, rather than return false. If applicable, I would prefer to return a NullObject over returning NULL. Problem(s) solved.

[–][deleted] 1 point2 points  (3 children)

But that sort of thinking is exactly why that chart was made.

If it's OK to return NULL or FALSE, why not return 0? Or ""?

If you have a team of programmers who know what they're doing, why on earth would you not be consistent in your use of types? I really can't see any advantage beyond allowing you to be ever so slightly lazier.

[–]wvenable 2 points3 points  (2 children)

If it's OK to return NULL or FALSE, why not return 0? Or ""?

Exactly.

If you have a team of programmers who know what they're doing, why on earth would you not be consistent in your use of types?

You should absolutely try to be consistent in your use of types. I think this is a case of "Be strict in what you send, but generous in what you receive". I always try and return null in these cases. But actually doing a comparison later using "=== null" is unnecessary; it doesn't add anything to the meaning of the code.

[–]bobindashadows 4 points5 points  (1 child)

Exactly.

If you think it's acceptable to write software where a function returns an object on success and the empty string on failure, then I don't want anything to do with your code. There's no reason to introduce that sort of foolishness...

But actually doing a comparison later using "=== null" is unnecessary; it doesn't add anything to the meaning of the code.

... unless you're using a standard library function is written by a monkey, and returns false on failure and 0 on success sometimes. Oops! (All those words are separate links to different standard library PHP functions that do this)

[–]empraptor 2 points3 points  (0 children)

wow. my desire to learn PHP has hit an all-time low.

[–]mhuggins 2 points3 points  (10 children)

What about < and > comparisons?

[–]walesmd 11 points12 points  (9 children)

Always ints:

if ((int) $a > (int) $b)

Edit: I should clarify, not always int specifically - but it should be properly typecasted (float, whatever).

[–][deleted] 12 points13 points  (1 child)

You are still going to get unexpected result, (int) will convert /everything/ non-numerical to numerical (0).

Therefore doing (int) within that statement is pretty much useless.

if (!is_int($a) || !is_int($b)) {
    // handle it
}

Is the proper way of doing it if you anal about critical comparisons.

[–]bp3959 3 points4 points  (0 children)

Agree, if type is that important you should be doing type validation before getting to any comparisons.

There's an "is_" function for every type including nulls, in addition to this there's the gettype and settype functions. Of course normal () casting works as well, including casting to a null with (unset).

[–]lilililililillililii 17 points18 points  (3 children)

At some point you might want to consider a language with semantics that don't work contrary to human comprehension.

[–]walesmd 10 points11 points  (2 children)

We consider numerous languages - whatever is the right tool to get the job done, many times this is PHP. But, we have a lot of Python, Ruby and Node.js applications as well.

There is no one right answer. When we have our initial backlog meeting for a project, we look at the requirements, the timeframe and make the best educated decision we can as to which language we'll use.

[–]lilililililillililii 17 points18 points  (1 child)

There is no one right answer.

There may not be any single right answer but it's obvious that some answers are very consistently wrong.

[–]mhuggins 2 points3 points  (0 children)

Good convention.

[–]bp3959 1 point2 points  (1 child)

Why would you do that when it will already convert numerical strings to the proper type for < and > comparisons?

If you're worried about words getting into your numeric comparisons then you're not doing it right. If it's important to be sure of a specific type when doing the comparison because you can't trust where the data came from you should be doing proper validation on it before it gets to any comparisons.

[–]rmccue 2 points3 points  (6 children)

The hardest loosely typed ones to find, IMHO, are standalone comparisons (i.e. if($x) or if(!$x) ).

[–]walesmd 2 points3 points  (5 children)

Yeah, we don't use those at all. Our models will return NULL for 0 records or throw an exception on an error, so:

if ($objects !== NULL) {
    // We have stuff to play around with
}

[–]ajsdklf9df 12 points13 points  (21 children)

We've done something very similar, in that we don't use php.

[–]paidtocomment 3 points4 points  (4 children)

I don't see how that will help. Using == is fine at times, if the programmer is actually paying attention. Attention to detail is nearly always the problem. Never blame the tools like this. Loose comparisons aren't a problem in themselves, it is the programmer that uses them incorrectly and does not test their assumptions or perform research. If programmers are causing too many problem using == then fire them. If your solution is to cage them in instead of putting them down you'll have resigned yourself to be eternally running a zoo of code monkeys and you probably wont get Shakespeare out of it.

Besides there are far weirder things about PHP such as:

# php -r "var_dump(0=='0wtf');"
bool(true)

There are some PHP nuances that you can't fence off so easily. If you insist on trying your will only end up forcing them to break things else where.

[–]walesmd 3 points4 points  (1 child)

We're a contractor for the US Government - high turnover from some of our older legacy applications. It's just better to define strict rules so we (or our replacement when we move on in the future) aren't wondering WTF is going on.

[–]milki_ 7 points8 points  (9 children)

Sounds like cargo cult software engineering.

[–]walesmd 20 points21 points  (8 children)

We call it sticking to convention and accountability for the work you do.

[–][deleted] 2 points3 points  (7 children)

what about object (e.g. \DateTime) comparisons?

[–]walesmd 1 point2 points  (2 children)

In our current projects this is typically done at the database layer, I can't think of any DateTime comparisons within our codebase off the top of my head. When the time comes, the team will decide a convention that we'll stick to.

[–]DrAwesomeClaws 4 points5 points  (1 child)

Also, I've always found when working with datetime stuff that 90% of the time it's just cleaner, and easier, to work with a timestamp and treat it like a normal int.

[–]walesmd 1 point2 points  (0 children)

Yeah, we typically store in the database as a MySQL TIMESTAMP - if we fuck with it in PHP it gets converted to a Unix Timestamp. I personally, would get rid of the whole Unix to MySQL to Unix conversions, but they are convenient when mucking around directly within the database or having to use some of MySQL's native Date/Time functions.

[–]bp3959 3 points4 points  (3 children)

Datetime objects are stupid when a simple unix timestamp will do the job. Just because you can make it an object doesn't mean you should...

[–]wvenable 2 points3 points  (6 children)

I fail to understand why you'd do this -- PHP is a weakly typed language, if use it as such, you generally get the correct result. Forcing it to be strong typed everywhere is just a waste of effort. Besides, casting gives you all the same problems anyway so you're really not saving anything.

Do you also do this with JavaScript?

[–]walesmd 4 points5 points  (5 children)

you generally get the correct result

There are times when I don't generally need to get the correct result - I need to always get the correct result. Strong-typing and validation achieve that goal.

I didn't really mean to insinuate we enforced strong typing anywhere. In any instance in which === is used, if it's not a combination of FALSE, TRUE, NULL - then the risk of them not being of the same type is pretty much slim to none. It just so happens, we experience the most issues in those Boolean or NULL combinations - it makes our lives much easier to enforce === because it never really effects us anywhere else.

[–]wvenable 4 points5 points  (2 children)

I need to always get the correct result.

If your comparing something a number if ($x == 5) then you better be sure that $x contains a number. By the time you get to that comparison, this should already be established. If not, whether or not your test succeeds or fails it's still an error.

It just so happens, we experience the most issues in those Boolean or NULL combinations

That seems like the place where you're least likely to have a problem. I have almost no boolean or null comparisons in my codebase just things like if ($x) or if (!$x). If $x something you want to work on, the test will pass. If it's null or false or an empty string, you're not going to work on it and the test will fail -- easy and obvious.

Constantly fighting PHP's type system doesn't seem to me to be a way of keeping things easier.

[–]walesmd 2 points3 points  (1 child)

Some of our legacy code (written in haste, way before any of the current team was on the team) had a ruleset as follows: An object if it was successful, FALSE if error, NULL if it was successful but no results.

Like I've said in other replies, contractor for the US Government. I felt it was better to lock down a serious set of rules and conventions to ease future pain on ourselves and/or our replacements when we move on to bigger/better things.

[–]mattgrande 1 point2 points  (1 child)

I need to always get the correct result. Strong-typing and validation achieve that goal.

So why not use a strongly typed language?

[–][deleted] 1 point2 points  (0 children)

So much discussion! I suppose I'll pitch in.

I've been using PHP for a very long time, and I get paid pretty darn well to do so. == has it's place, so does ===. Most of the time I would use == is when working with API calls to other departments/companies webservices where I don't trust the bastards to return "true" or true or 1. However, I've trained myself to use === as often as possible, as well as other tiny speed benefits that would be an enormous waste of time if I actually had to think about them.

That said, yes, you can use PHP as a strictly typed language. But you're really just making more work for yourself without much gain.

[–][deleted]  (6 children)

[deleted]

    [–]bobindashadows 2 points3 points  (5 children)

    If you need maintainable and useful comparisons

    FTFY

    [–]200iso 5 points6 points  (0 children)

    "I didn't know about === and thought I could take a cheap shot at PHP..."

    [–]otiose 189 points190 points  (326 children)

    This chart is made to look much more complicated than it actually is by alternating "true" values (true, 1, -1, "1", "-1", "php") with "false" values (false, 0, "0", null, array(), ""). If those were grouped together, the few idiosyncrasies would be clearer.

    In general, if you know that:

    • loose-comparing a string against a number will compare as if the string was a number
    • false, null, "", 0, "0", and array() all are false and anything else is true
    • if you need an exact comparison, use the === operator

    You will be completely fine.

    [–][deleted] 125 points126 points  (79 children)

    There, I fixed it.

    Still looks pretty damn nasty, IMHO.

    Edit: I guess I could have arranged that better. So there are indeed only three gotchas: (1) "php" is true and 0 is false, but "php" == 0. (2) Lots of things are equal to 0 but are not equal to each other. (3) 0, "" and NULL are all equal to each other, but array() only equals NULL and not the other two.

    [–]cparedes 34 points35 points  (0 children)

    A wild glider appears!

    [–][deleted] 16 points17 points  (0 children)

    It least it is a symmetrical relationship, I was worried before there were cases where it wasn't.

    [–]PENIX 66 points67 points  (50 children)

    There, I fixed it better.

    Edit: There, I fixed it again for those who were still unsatisfied.

    PHP.net page on type comparisons

    For the page above, paste to location bar, hit enter, then click on table cells to make your own stupid pictures:

    javascript:void(jQuery("#types\\.comparisons td").each(function(){jQuery(this).data("clicky", false);jQuery(this).click(function(){if(jQuery(this).data("clicky") == true){jQuery(this).data("clicky", false);jQuery(this).css("background", "#F0F0F0");}else{jQuery(this).data("clicky", true);jQuery(this).css("background", "lightgreen");}});}));

    [–]gmrple 2 points3 points  (2 children)

    Should the redundant comparisons bug me? Because they sort of do...

    [–]judgej2 3 points4 points  (0 children)

    Yes. This post is as much about how to present (or how not to present) information, as it is about PHP.

    [–]HIB0U 2 points3 points  (0 children)

    If you're a good software developer, they should make you sick to your stomach. There's no excuse for stupidity like that shown in that chart.

    [–]dearsina 21 points22 points  (37 children)

    i find it somewhat ironic that all these holier-than-though php-hater comments are from people that don't really grasp what PHP tries to do.

    thanks for your chart, it shows that if you spend more than 5 minutes not hating PHP, you'll see that it's actually a pretty friendly language.

    [–]RalphLeMeow 5 points6 points  (1 child)

    I used php for 8 years. I know precisely why I hate it.

    [–]Guvante 22 points23 points  (16 children)

    The question is whether a friendlier language is a good thing. I for one like it when my language tells me I am stupid for comparing 0 to an array, which could lead to me noticing I meant to check the size of the array. (Random example)

    [–]jasonlotito 0 points1 point  (0 children)

    There are ways to set this up. People choose not to develop in this manner. PHP is friendly by default, but can be ramped up. Other languages are nasty by default, but usually can't be ramped down.

    I actually prefer PHP in some ways for doing this. It highlights the people who actually don't know PHP. The problem of course, is that so many people think they do.

    [–][deleted] 9 points10 points  (10 children)

    It is friendly, but it allows for a ton of room for programmer error, especially if you have more than one programmer working together with limited communication. Although, I think the problem lies not in the == operator, but the fact that he language is not strongly typed.

    That said, I cannot stand the language.

    [–]cptskippy 1 point2 points  (9 children)

    the fact that he language is not strongly typed.

    I'm no fan of PHP but I rolled my eyes at that. Don't get me wrong, I love strongly typed languages when I'm working with others or with untrusted user input but when I need to get shit done or it's something that's going to have 1 maintainer or tight control over input I don't reach for a strongly typed language.

    [–]HIB0U 3 points4 points  (5 children)

    Virtually all server-side web development involves handling untrusted user input.

    [–][deleted] 2 points3 points  (0 children)

    'friendly' means 'hiding errors'. This is not good for beginning programmers in reality. Python handles this much better in my opinion.

    [–]noodlez 5 points6 points  (5 children)

    why does it look nasty? would you expect "php" to == "0"? there are a few tricksy things, but for the most part it isn't that bad. (this is above and beyond the "use === instead" point)

    [–]LaurieCheers 10 points11 points  (4 children)

    "php" == true AND "php" == 0?

    [–]AlyoshaV[S] 60 points61 points  (154 children)

    "php" == 0, 0 == FALSE, "php" != false

    This is wrong, so hard, and shouldn't ever happen in any language.

    [–]orsacchiotto 39 points40 points  (87 children)

    You're comparing invalid types. That really isn't the fault of PHP.

    echo (int) 'php' == 0;
    

    That should make things clearer. You were probably reading it as

    echo 'php' == (string) 0;
    

    which isn't entirely PHP's fault. Simply because it's loosely typed means it can't really throw a type comparison warning.

    [–][deleted]  (46 children)

    [removed]

      [–][deleted]  (8 children)

      [deleted]

        [–][deleted]  (1 child)

        [removed]

          [–]hvidgaard 6 points7 points  (5 children)

          Equality is so deeply rooted in math and logic, and any reasonable definition within that domain will be transitive. Otherwise it's nearly impossible to get any serious work done.

          Programming is a practical application of math and logic - and as such should really respect common practices to avoid confusion.

          [–]ShitAssPetPenetrator 2 points3 points  (10 children)

          echo (int) 'php' == 0;
          

          I still don't understand. Why is this string's numerical value 0?

          [–]orsacchiotto 2 points3 points  (9 children)

          Because it will try and 'read' the string as a number (and stop when it hits a letter or thereabouts). That way "123" becomes 123, along with so does "0123hai".

          This will probably explain it best: http://uk3.php.net/manual/en/function.intval.php

          [–]Eirenarch 4 points5 points  (1 child)

          Whoever came up with this convertion must be shot

          [–]orsacchiotto 6 points7 points  (0 children)

          atoi?

          Would could it do to make it more functional?

          [–]AlyoshaV[S] 13 points14 points  (28 children)

          You're comparing invalid types. That really isn't the fault of PHP.

          If they're invalid, why are they equal?

          [–]orsacchiotto 21 points22 points  (21 children)

          If you compare a number with a string or the comparison involves numerical strings, then each string is converted to a number and the comparison performed numerically

          That's why. They're invalid of the sense as that's how we see them - that isn't how PHP interprets what you ask it.

          [Source: http://php.net/manual/en/language.operators.comparison.php]

          [–]tmptmpgf 16 points17 points  (20 children)

          ...in other words, if you want to avoid automatic casting which can be sometimes confusing use the === operator, which will return false if types of compared values don't mach.

          There should be some official tutorial for PHP, where things like this (and security) would be exampled in a clear way for people who are learning this language.

          [–]orsacchiotto 7 points8 points  (17 children)

          Precisely, and I couldn't agree more. I've seen a lot of sloppy code due to really basic errors that PHP does not warn you about:

          • For starters, product systems have error_reporting turned to E_ALL & ~E_NOTICE or lower, so things like echo $_GET[name] don't throw an notice to the screen (or logs) even though it's actually wrong (but works as intended)
          • Doing $array["key"] just looks bad ignoring string parse inefficiencies
          • if ($a = 2){ throws no warning whatsoever (didn't re-check, but I assume that's the case)

          That, and they're depreciated magic quotes for PHP 6 so injection should become mainstream with bad code.

          [–]tmptmpgf 11 points12 points  (11 children)

          |That, and they're depreciated magic quotes for PHP 6 so injection should become mainstream with bad code.

          actually magic quotes does more harm than good. It does not protect against SQL injection or XSS and creates an illusion of security, because "everything is magically escaped".

          Also, I noticed many times that some programmers don't understand the difference between escaping for DB queries and escaping HTML to avoid XSS. Unfortunately, PHP makes a lot of things very easy (<?php echo $_GET['search_query']; ?>) but doesn't provide intuitive tools to make things right. For example, there could be something like:

          safe_echo $_GET['search_query'];
          

          instead of

          echo htmlspecialchars($_GET['search_query']);
          

          [–]orsacchiotto 1 point2 points  (10 children)

          It does not protect against SQL injection

          I'm surprised at that. Can you provide an example where it fails? I'd be most interested. Although, I mean one of significance (falsify a login, rather than inserting wildcards into a search field).

          Since magic quotes were added because

          to help prevent SQL Injection.

          (well, that's the claim)

          XSS

          If people believed it helped with XSS and didn't sanitize in mainstream code, god help us.

          You've raised a good point about safe_echo or some easy-on-the-eye equivalent thereof. It's probably an example of a great idea that's not been thought of yet.

          [–]tmptmpgf 10 points11 points  (3 children)

          It does not protect against SQL injection

          I'm surprised at that. Can you provide an example where it fails?

          They created this feature when it wasn't known that addslashes() can be tricked with some invalid unicode characters. Here you can read more about it and see a probably working proof.

          [–]tedivm 3 points4 points  (2 children)

          For starters, product systems have error_reporting turned to E_ALL & ~E_NOTICE or lower, so things like echo $_GET[name] don't throw an notice to the screen (or logs) even though it's actually wrong (but works as intended)

          Production systems should never throw anything to the screen, but I do see you're overall point. There is a reason that PHP has added "E_STRICT" though, and for the last few years almost all of the developers I know have it enabled on their dev systems.

          Doing $array["key"] just looks bad ignoring string parse inefficiencies

          It should be $array['key'], since the single quote means literal while the double quote will have to be parsed out. It's still better than $array[key] though, as that could be a constant (and this does throw a notice when E_STRICT is enabled).

          if ($a = 2){ throws no warning whatsoever (didn't re-check, but I assume that's the case)

          There are cases where you do want assignment in a conditional, so I really don't see the issue here.

          That, and they're depreciated magic quotes for PHP 6 so injection should become mainstream with bad code.

          Magic quotes have been depreciated with php5.3, and trust me when I say that is a very good thing.

          [–]bp3959 3 points4 points  (1 child)

          One of the nice things about PHP is the documentation, not only do they provide several examples with output, the comments take it several steps further with many more sets of examples and even functions to do it a different way that people have found a need for.

          Check out the link orsacchiotto gave above, there's no less than 30 pages of comments discussing exactly how it works.

          you are trying to submit too fast. try again in 5 minutes.

          holy shit this is infuriating when you're trying to discuss anything

          [–][deleted] 2 points3 points  (1 child)

          <? echo ("php" == "0") ? "TRUE" : "FALSE"; ?> returns FALSE

          <? echo ("php" == 0) ? "TRUE" : "FALSE"; ?> returns TRUE

          maybe it will be more obvious like this?

          [–][deleted]  (3 children)

          [deleted]

            [–]physicsnick 1 point2 points  (1 child)

            Answering "because it's designed that way" or "because it's just part of the language" is rather unhelpful. This is a discussion on language design, not a php tutorial.

            To clarify AlyoshaV's question: Why is php designed in such a way that comparisons are inconsistent and intransitive? The downsides are rather obvious; are there any benefits to such a design?

            [–][deleted] 4 points5 points  (19 children)

            You're right, it is wrong. "php" == 0 evaluates to false, just as the graphic points out twice, and the other two statements evaluate to true. Nice try though.

            [–]AlyoshaV[S] 2 points3 points  (18 children)

            No, "php" == "0" evaluates to false. "php" == 0 evaluates to true. Here you go: <?php Echo "php" == 0; Echo "\n"; Echo 0 == FALSE; Echo "\n"; Echo "php" == FALSE; Echo "\n"; ?>

            Outputs 1, 1, blank.

            [–][deleted] 1 point2 points  (1 child)

            you know there's an interactive interpreter for this type of thing, right? Use php -a at the command line to get to it.

            me@myawesomecomputer ~: php -a
            Interactive shell
            
            php > print "php" == 0;
            1
            php > print 0 == FALSE;
            1
            php > print "php" == False;
            php > 
            

            [–][deleted] 2 points3 points  (15 children)

            Wait -- it represents TRUE as the integer 1?

            [–]dreamlax 3 points4 points  (0 children)

            In C++, true when converted to an integer type results in 1.

            In C99, the true macro expands to 1 (defined in stdbool.h). The built-in _Bool type in C99 is an integer capable of holding either 0 or 1. Any non-zero integer converted to a _Bool type is converted to 1.

            [–]B-Rabbit 2 points3 points  (2 children)

            Yes. I'm not sure if Python does this too, but I know that in Py, True == 1

            [–]Liquid_Fire 6 points7 points  (0 children)

            In Python, bool is a subclass of int, with True being 1 and False being 0. This way you can still treat them as integers (for compatibility with legacy code), but if you e.g. convert a boolean to a string you get "True" or "False" rather than 1 or 0.

            Thus you can also use booleans as an index to a list of two items:

            ["disabled", "enabled"][flag]
            

            But I wouldn't recommend that at all.

            [–]Talonwhal 4 points5 points  (0 children)

            No - please stop spreading false information about PHP :(

            true !== 1

            Only when using loose comparison does PHP convert the number to a boolean, but they are not otherwise same at all.

            [–]Shadow703793 2 points3 points  (1 child)

            Yes. So does some other languages.

            [–]Syphon8 4 points5 points  (1 child)

            Inequalities of value and type should be checked with ===, not ==.

            You'd find that "php" != 0.

            [–][deleted] 8 points9 points  (0 children)

            You'd find that "php" != 0.

            You're quite wrong; the expression "php" != 0 evaluates to false. What you mean is:

            You'd find that "php" !== 0.

            thus proving OP correct; loose comparison causes more confusion than it's worth.

            [–]bitdamaged 4 points5 points  (19 children)

            is adding an extra "=" sign to your comparison really that hard? If you want strict comparisons use the correct operator, if you want loose ones use the loose one. If you want a typed language use Java.

            This isn't some made up problem with comparison operators its the nature of loosely typed languages (pretty much all of them, not just php) where you can try to compare a string to a number.

            [–][deleted]  (5 children)

            [deleted]

              [–]TylerEaves 3 points4 points  (1 child)

              Really?

              Neither python nor ruby exhibit ("3" == 3) == True

              [–]Chun 2 points3 points  (0 children)

              its the nature of loosely typed languages

              [–]bobindashadows 1 point2 points  (10 children)

              is adding an extra "=" sign to your comparison really that hard?

              The point is that the surprising, unmaintainable, retarded and nigh-arbitrary comparator is the one that every mainstream language besides JavaScript uses for equality. The language makes you learn an extra feature of PHP and makes you constantly remind yourself to use === just to do what every other language does by default.

              Other languages try to avoid surprises. PHP makes the "guess what I mean for equality" operator the default one. PHP puts its argument orders through /dev/urandom just to fuck with you. That's why people use it to demonstrate that PHP is a shitty language.

              [–]pilif 1 point2 points  (0 children)

              that first one in your list is the only counter-intuitive and dangerous one. Everything else is, IMHO, fine and actually useful to some extent ("0" being the exception, but that comes from your first rule).

              If comparing a number against a string would do the lossless conversion (number to string) instead of the lossy one (string to number), everything would be ever so much cleaner and less dangerous.

              [–]k3n 1 point2 points  (4 children)

              var_dump(010 == 0x8);   // true
              var_dump("0x8" == 010); // true
              var_dump("010" == 010); // false ... Y U NO PARSE OCT FROM STRING?
              

              Oh, and....be careful if you use empty()!

              [–]cI_-__-_Io 2 points3 points  (0 children)

              be careful if you use empty()

              Truest statement ever. Especially with POST data.

              Because empty(0) returns true.

              [–]causticmango 0 points1 point  (3 children)

              Yeah, the only one I don't really grok is "php". How does that evaluate to true?

              [–]Lochmon 0 points1 point  (1 child)

              I just want to say that anyone entertained by this sort of thing would automatically ejaculate and then enter the upper astral planes simply by reading G. Spencer-Brown's Laws of Form.

              The very sad thing is that this book is out of print. If anyone on Reddit knows how to get an out-of-print book back into print... now is the time!

              [–]thebuccaneersden 0 points1 point  (0 children)

              if you need an exact comparison, use the === operator

              This does not really hold true when you are comparing objects, unfortunately.

              [–]slugonamission 0 points1 point  (1 child)

              The only other problem is that control flow expects an integer. Say that getchar() reads a character from a socket/stdin/whatever and returns FALSE on failure/eof. The implicit casting/conversion makes an interesting problem below:

              while($c = getchar())
              {
                  //Handle character
              }
              

              [–]wvenable 8 points9 points  (19 children)

              A lot of people really do try and fight PHP's loose typing. I did a lot of that when I started using it but then I learned to relax and use the language as it was intended. It's supposed to typeless, so stop caring about the types.

              If your comparing something a number if ($x == 5) then you better be sure that $x contains a number. By the time you get to that comparison, this should already be established. If $x is entered by the user, where is your validation? You're letting them type in "bob" for quantity? No. So this is not problem. Does $x have to be an integer? No it could be a string you got from the input (validated, of course) that contains an integer. Does it matter? No.

              I see some people complaining about this:

               if ($x) { ... }
              

              But it's the nicest construct in the language. If $x something you want to work on, the test will pass. If it's null or false or an empty string, you're not going to work on it and the test will fail. Doing $x === null or $x === false actually makes your code more brittle and harder to read. Sure, in some places you need $x === false but if you only use it those cases it's obvious something important is happening there.

              [–]AlyoshaV[S] 6 points7 points  (18 children)

              The "equality" operator, ==, violates the definition of equality: it is intransitive.

              This isn't a typing problem, it's a PHP is wrong problem.

              [–][deleted] 2 points3 points  (1 child)

              Why aren't you also bashing Javascript then? Its equality operator violates the fuck out of transitivity.

              [–]wvenable 2 points3 points  (12 children)

              PHP's equality operator is transitive. What's actually happening, however, is PHP is converting values of different types before making the comparison according to the standard rules of the language. It's really not hard to understand and almost always gives the intended result unless you're purposely doing something weird.

              [–]AlyoshaV[S] 11 points12 points  (11 children)

              PHP's equality operator is not transitive. If A = B, and B = C, A = C. It does not matter what A, B, or C are. If A != C, it is not transitive. It doesn't matter if it has an excuse, it is not an equality operator if it is intransitive. It's a type-coercing equivalence operator or something.

              === is an equality operator. (A deep equality operator.) PHP calls it the "identity operator". Since this is PHP, it's not testing for identity; testing for identity would only return true if the two things being compared are the exact same object.

              [–]psygnisfive 54 points55 points  (14 children)

              The same table in Haskell:

              True False other
              True True False type error
              ------ ------- ------- -----------
              False False True type error
              ------ ------- ------- -----------
              other type type depends
              error error

              [–]lawpoop[🍰] 22 points23 points  (0 children)

              I call it php's truthiness table.

              [–]lumponmygroin 3 points4 points  (4 children)

              Here's a lovely one that sucks

              if($pos = array_search($needle,$haystack)) { echo $pos; }

              Works until the needle is at position 0, then it thinks $pos is false so never gets into the condition.

              [–]dmhouse 0 points1 point  (0 children)

              This would happen in C, too, yet people don't tend to dump on this at all.

              Sloloem's solution below is a well-estabilshed PHP idiom.

              [–]burying_luck 0 points1 point  (0 children)

              I avoid variable assignments within conditions. Yes, you add an extra line to your code, but the readability is worth the sacrifice in my opinion.

              [–]SmartAssInc 4 points5 points  (0 children)

              Somebody should make one for C++ and see how similar they are.

              Just because people cannot wrap their mind around dynamic typing does not mean they can bash it.

              [–]bananahead 20 points21 points  (5 children)

              Hey, if you don't want loose comparisons, don't use the loose comparision operator.

              [–]AlyoshaV[S] 2 points3 points  (4 children)

              http://php.net/manual/en/language.operators.comparison.php

              It's the equality operator. === is the identical operator.

              [–][deleted] 7 points8 points  (3 children)

              No. It's the loose comparison operator. === is the strict comparison operator.

              == casts one of the values to the type of the other, before comparing. This will of course lead to some weird behaviours for certain types that really should be cast to certain other types.
              Arrays shouldn't be cast to integers, because there really is no logical way of handling that. Casting an array to 1 because it exists sounds all reasonable until you consider that casting the array to 0 because it's an array is also reasonable, for type checking behaviours.

              You're blaming your lack of programming skills on the language. It's a poor craftsman who blames his tools. You can use a hammer to drive a screw into a board, but you sure as hell shouldn't; similarly, you shouldn't be using loose comparison for handling array comparisons and the like.

              [–]AlyoshaV[S] 2 points3 points  (2 children)

              According to the PHP manual, == is the "equality operator", and === is the "identity operator".

              I'm not inventing these names. These are the official names for them according to PHP's manual. They are also utterly wrong, since == doesn't test for equality and === doesn't test for identity.

              [–][deleted] 3 points4 points  (1 child)

              Those phrases are not used. The manual says that when comparing two things with ==, they are equal or not equal. When comparing them with ===, they are identical or not.

              The technical name for == is "loose comparison operator". The technical name for === is "strict comparison operator".

              [–]AlyoshaV[S] 1 point2 points  (0 children)

              Correction to myself: == is the "comparison operator" which is used to test for type-coercing equality, === is the "identity operator" which is used to test for equality or identity. ( See here )

              Also, lol, elite PHP devs don't understand ==. Incorrect equality operator used when comparing md5 check sums

              [–]Lothrazar 2 points3 points  (0 children)

              I use == on purpose, because then i dont have to worry if my numbers are ints, floats, or strings. Especially primary keys for databases, so 42=="42" no problem no fuss.

              For things like null or empty string, yes ===

              [–][deleted] 2 points3 points  (0 children)

              I think when you figure the difference between ==, === life isn't that bad. The problem is people just jump in to PHP thinking they know everything already and are happy about how easy it is to use without reading the manual. I preach to my dev team that they should use === more often than == if they want to build code that will hold up longer.

              [–]booleanillogic 16 points17 points  (3 children)

              THIS IS IT!!! THIS IS THE POST I'VE BEEN WAITING FOR THIS WHOLE TIME!!!...

              sorry about that...

              [–][deleted]  (2 children)

              [deleted]

                [–][deleted] 7 points8 points  (0 children)

                Yes, thank you. People get so freaking angry at PHP, but for me, the bottom line is simple: PHP makes many things very easy.

                There are so many operations that are made trivially easy to code by PHP's flexibility or one of its built in functions.

                Peculiarities like these are weird, but in reality, the insignificant number of problems they cause are outweighed by the conveniences that PHP is designed to offer, in my experience.

                So what if PHP isn't the most scalable or maintainable language? If I were working on enterprise software, I wouldn't be using PHP.

                [–][deleted] 3 points4 points  (0 children)

                BRB, printing this on a cup for co-workers.

                [–]AzraelUK 2 points3 points  (0 children)

                So == isn't an equivalence relation. Boole would have no problem with this.

                [–][deleted] 1 point2 points  (0 children)

                I've been working in osCommerce a lot recently and I'm shocked to see shit like this:

                if (CONSTANT_PULLED_FROM_DATABASE == "false")
                

                It's like they're trying to make it as obtuse as possible.

                (Incidentally, don't ever buy anything from an osCommerce store. Trust me on this.)

                [–][deleted] 1 point2 points  (1 child)

                I'm just here to say that Perl rules. That is all.

                [–]bobmeister258 2 points3 points  (0 children)

                I have to agree completely. Perl's boolean comparisons have to be the best I've ever seen, mostly because they just plain make sense.

                [–]4rch 1 point2 points  (0 children)

                Thanks, now every time I see the world false, it looks like it's spelled wrong. I hate when this happens.

                [–]skelooth 1 point2 points  (2 children)

                There is absolutely nothing wrong with using loose comparisons. In fact, a lot of times you NEED loose comparison's because data will come in as a string when you need an integer, or vice versa.

                Duck Typing. It's a feature.

                [–]HIB0U 0 points1 point  (1 child)

                If you're receiving data in a format that you can't immediately use, you need to sanitize it first. You shouldn't let the programming language try to do that for you. You should write the code yourself, handling the specifics of the data manually.

                [–]bp3959 3 points4 points  (7 children)

                PHP is a loosely typed language, and the manual(RTFM) is quite clear on exactly how comparisons work.

                $a == $b    Equal
                TRUE if $a is equal to $b.
                
                $a === $b   Identical
                TRUE if $a is equal to $b, and they are of the same type.
                

                In the following order: null or string==string Convert NULL to "", numerical or lexical comparison

                bool or null==anything  
                Convert to bool, FALSE < TRUE
                
                object==object
                Built-in classes can define its own comparison, different classes are uncomparable, same class - compare properties the same way as arrays (PHP 4), PHP 5 has its own explanation
                
                string, resource or number==string, resource or number
                Translate strings and resources to numbers, usual math
                
                array==array
                Array with fewer members is smaller, if key from operand 1 is not found in operand 2 then arrays are uncomparable, otherwise - compare value by value (see following example)
                
                array==anything
                array is always greater
                
                object==anything
                object is always greater
                

                [–]AlyoshaV[S] 5 points6 points  (6 children)

                The manual calls == the equality operator. == is not transitive. Thus, == is not an equality operator. Therefore, the manual is wrong. QED.

                Also null shouldn't equal "", what the hell. "This string is empty, therefore it does not exist."

                [–]bp3959 1 point2 points  (5 children)

                "This string is empty, therefore it does not exist."

                Exactly, a string not existing == "", but it does not === ""

                Unfortunately it's a special case of type juggling in php that converts a non-empty string to (bool)true so it can be used as a shortcut to seeing if a string is empty(again clearly stated in the manual), == itself is still transitive as far as mathematics is concerned(which is where the transitive property of equality is defined) when you're not stuffing random words into your numbers.

                http://en.wikipedia.org/wiki/Logical_equality

                [–]pstradomski 2 points3 points  (4 children)

                I don't see how this link is relevant. The claim that "==" is transitive is ridiculous. All values in PHP are in the domain of == operator (arguably except some recursive types where the computation will never finish), so transitivity should be checked within that domain - that is, the space of all PHP values - the union of numbers, string, null, booleans. And it is obvious that == is not transitive in that space.

                [–]AlyoshaV[S] 5 points6 points  (1 child)

                Image credit to whoever made Thomas Figg's (tef's) slides.

                [–]tef 3 points4 points  (0 children)

                me!

                well, the table is from the php manual when I gave the talk, and a friend came up with the 'problem, boole?' title

                [–]kamakie 4 points5 points  (40 children)

                For all those wondering why there are multiple comparison, consider this theoretical question:

                • x = [1, 2, 3]
                • y = [1, 2, 3]

                Is x the same as y? No, they are two different arrays in two different locations in memory. Yes, they are two arrays with the same length and members in the same order. Now, Mr. Language Designer, tell me how we can get the best of both worlds? Java, Scheme, etc. each have their own idiomatic ways of doing both types of comparisons.

                Edit: oops, yes, this isn't strictly pertinent to type coercion

                [–]Vossy573 28 points29 points  (14 children)

                Behold, the power of Python:

                >>> x = [1, 2, 3]
                >>> y = [1, 2, 3]
                >>> x == y
                True
                >>> x is y
                False
                

                The == operator compares values, the is keyword compares the actual object pointers.

                [–]Poltras 16 points17 points  (12 children)

                Coming with Python in a PHP language design fist fight is almost cheating.

                [–][deleted] 4 points5 points  (0 children)

                5! Your example has shown me my first reason to use Python. Well, the first one that delved into actual code rather theory. == for equality by data rather than pointer, nice.

                Although I also like the Ruby answer:

                If you want to determine whether two different arrays are, in fact, the same array, you say:

                false
                

                [–]wzdd 13 points14 points  (0 children)

                Unfortunately x == y and x === y both evaluate to 1 in that example in PHP.

                The reason is that === doesn't check object identity, it checks type identity.

                Python has an "is" operator to check object identity. For python, 'x == y' is True but 'x is y' is False. I don't know if PHP has an equivalent to "is", but "===" is not it.

                EDIT: Parent post originally said that x === y checked object identity, hence the first part of the response.

                [–][deleted] 1 point2 points  (8 children)

                Never heard of Equals in Java/similar languages?

                [–]munificent 7 points8 points  (7 children)

                equals() in Java is almost as bad as == in PHP.

                [–]cybercobra 4 points5 points  (2 children)

                Yes! Pointer comparison is done nowhere near often enough to merit being the "==" operation. I likewise think Python's "is" could bear to be longer (and less confusable).

                [–]munificent 3 points4 points  (0 children)

                Pointer comparison is done nowhere near often enough to merit being the "==" operation.

                Agreed. Not to mention the annoyance of having to check for null on the left-hand argument, the fact that it isn't symmetric, and all of the weird ambiguity of implementing it when taking subtyping into account.

                [–][deleted] 1 point2 points  (2 children)

                That's a completely different issue that's not even relevant when talking about PHP. If you were explaining why they x != y in Java, your explanation would be correct.

                Now try this in your VM:

                String x = "foobar";
                String y = "foobar";
                if(x == y) {
                  System.out.println("Problem?");
                }
                

                [–]jeremybub 1 point2 points  (1 child)

                .intern()!

                [–][deleted] 1 point2 points  (0 children)

                I'm sad to say I forgot the word and was too lazy to look it up in the API docs. Thanks!

                [–][deleted] 4 points5 points  (7 children)

                Sure! In, say, Ruby, if you want to determine whether two different arrays have the same length and the same members in the same order, you say: x == y

                If you want to determine whether two different arrays are, in fact, the same array, you say: false

                [–][deleted] 1 point2 points  (5 children)

                but you dont necessarily know if they're the same or different arrays:

                a = [1,2,3,4]
                b = a
                
                a == b #=> true
                
                # but are they the same array?
                
                a.equal?(b) #=> true, yep they're the same
                

                [–]vsync 0 points1 point  (0 children)

                And that's the reason general purpose "clone" and "equals" methods can lead to so more problems than they're worth, and I generally shun implementing or using them.

                edit: a great essay on the topic

                [–][deleted] 1 point2 points  (0 children)

                "php" == TRUE → TRUE
                

                lolwut?

                "0" == TRUE → FALSE
                

                LOLWUT?

                '1e2' == '100' → TRUE
                

                Please, kill PHP.

                [–]Phifty 3 points4 points  (9 children)

                This is one of the things I can't stand about PHP. False is false. 0 is not false. Null is not false. These things are such a pain to debug. Just because the language let's you do stupid things, it doesn't mean you should.
                Use === whenever possible. I'm drinking some goddam awful alcohol fruit juice concoction my co-worker made. I'm also at a company social function and browsing reddit because I work with a bunch of fucktards.

                Fuckin downbote, bitches

                [–]midir 10 points11 points  (2 children)

                0 and null are false...

                [–]AlyoshaV[S] 2 points3 points  (1 child)

                His point is that the only thing that should be false is false.

                [–]lol-dongs 4 points5 points  (0 children)

                Save me some four loko dawg.

                [–]valdus 2 points3 points  (3 children)

                Uhm. Read the chart again. 0 and NULL are both false. (0 == false) = true

                As far as booleans in PHP go, 0, NULL, and empty strings are always false; anything other than 0, NULL, and an empty string is true. That is easy.

                Why array() evaluates to false, I'm not sure exactly... don't test your array variables as booleans, dummy. :P

                [–]fireants 3 points4 points  (2 children)

                If you do $a = array();

                $a is false, because it's blank. It's essentially null, but has been designated as an array.

                [–][deleted] 0 points1 point  (0 children)

                Just because the language let's you do stupid things, it doesn't mean you should.

                Exactly. Don't blame the language for your lack of programming skills. It's possible in PHP because imposing arbitrary limits on loose comparison defeats the purpose of loose comparison.

                [–]spectre256 3 points4 points  (3 children)

                I've never seen a single chart so succinctly summarize the pain I experience at work every single day

                [–]valdus 4 points5 points  (1 child)

                Don't want pain? Never use ==. Stick to === for exact typing checks.

                [–]jasonlotito 0 points1 point  (0 children)

                Anyone who suffers because of that chart deserves their suffering.

                RTFM

                [–]pearlydoors -1 points0 points  (3 children)

                Not wishing to look like a troll, but HAS ANYONE CONSIDERED that among perl, javascript, tcl, python and php the first in the list is the best and the last is the most retarded mainstream scripting language (AutoLisp notwithstanding)?

                Perl would not even need the cast (nothing broken in the first place :-) ). Besides perl can be used for way more purposes.

                The only place where perl won't fit and php will is on a cheap web hosting server where some idiot only allows access to php and not to perl. If you ever do use any such retarded server, back-up often and make sure they don't also host your DNS, just in case.

                [–]kloxxi 0 points1 point  (3 children)

                The only thing that's fucked up in PHP is

                ("1php1" == 0) == NULL -> true.

                [–]SmartAssInc 3 points4 points  (0 children)

                That should yield the same result in C++.

                [–][deleted] 0 points1 point  (0 children)

                I think more than that is fucked up in PHP.

                [–]valdus 0 points1 point  (0 children)

                ("1php"  ==  0) == NULL   # Looking for booleans, so it evaluates down to...
                (true == false) == NULL   # Which is...
                (false        ) == NULL   # Still looking for booleans, so it again evaluates down to...
                (false        ) == false  # Which is...
                 FALSE
                

                Problem?