Comparison order in PHP IF - php

I'm pretty sure that there is no difference between this
if ($value === true)
and this
if (true === $value)
For me it always seems confusing. I used to think that it's a 'bad unconventional style of new developers'. Furthermore, my boss told me never to do such a thing.
But today I was looking through Slim's source code, written by the guy who created PHP: The Right Way, and saw this (line 341).
if (true === $value) {
$c['settings'] = array_merge_recursive($c['settings'], $name);
}
I'm sure a guy like Josh Lockhart wouldn't do something like this if it was considered a bad practice. So what's with this order? Is it some kind of an old tradition?

This is colloquially referred to as 'Yoda Conditions'. The reasoning behind their usage is because sometimes people make mistakes. In the context of an if statement, this is one such mistake that is sometimes made:
if($value = 42)
Notice there is no double equals sign (==). This is a valid statement and is not a syntax error. It is possible that it would cause huge disruptions with the code that follows it, and it is very hard to identify quickly. Yoda conditions get around this by reversing the conditional expression:
if(42 = $value)
This is not a valid statement and is a syntax error, and those are generally reported with a line number included, so they're pretty easy to find.
"Syntax error you have. Line 73 do something else you must." -- Yoda's compiler, probably
Whether or not you actually think they're good or bad is up to personal preference and style. In some cases of popular frameworks (such as Wordpress), Yoda conditions are actually part of the official coding standards. The major critique against them is that, to some, they decrease readability of the code without providing any real major benefit.
As #MonkeyZeus pointed out in a comment to the question, sometimes people do actually mean to only use a single equals sign inside of an if condition:
if($iMustHaveAValue = functionCallThatCanFail()) {
// Rest assured, $iMustHaveAValue has a truthy value.
}
Since the value of an assignment operation is the value assigned, the value that is evaluated by the if condition in this case (and in the original case which was unintended) is whatever value happened to be assigned.

Related

PHP # instead of isset to test a $_GET value

Give me one good reason to do this
if( isset($_GET['key']) && ($_GET['key'] === '123') )
{...
instead of this
if( #$_GET['key'] === '123' )
{...
I'm asking for this very specific code case, and not in general!
Following reasons are not welcome:
"using # will slow down the application by some nanoseconds because the
error is created anyway (even if it's supressed)." Well I prefer slower
code but more readable.
"using # is bad habit." It might be true in general, but I don't belive in this case (moreover bad habits might
depend on the context, on PHP manual in function like fopen they
suggest to use # in certain circumstainces, see Errors/Exceptions
at http://www.php.net/manual/en/function.fopen.php)
The performance impact isn't actually the best argument against this example and you would have to measure the performance in your own application to decide whether this is a problem. It is more likely to cause a slow down if a large number of items being checked are not set or if you placed a check such as this within a loop.
The main problem associated with using the # operator is that it is likely to become a convention in your code, so while your example may seem innocuous, you may later find yourself or your team using:
if( #IsAvailable() ) {
And the error suppression starts to hide real errors that you didn't anticipate as well as those that you did - and you have no idea what happened as you get no exception information at all.
Think about how much you could be slowing your application down when your website / app starts getting tens / hundreds of thousands (or more) of requests a day. If you're suppressing errors as a standard, you probably have dozens for every request - suddenly, you're site is noticeably slower than you would want it to be.
In addition to this, you could end up suppressing errors that you actually want to be aware of while developing.
If you don't take performance issue as argument, then it is indeed OK. But it does not has to be in all cases, because # will supress all possible errors, even those, you did not think about. But in this case, it seems there are not possible other errors that the one you want to supress.
I agree with you that preceed isset() before reading value is very ugly and I don't like to write it either. But insert # before statement seems ugly to mee to. It can decrease readibility in longer code.
Good news is, that since PHP 7 we can use much nicer way, null-coalescence operator ?? which works like this:
if($_GET['key'] ?? '' === '123' ) {}
It is basically replacement for this:
$result = isset($value) ? $value : $anotherValue;
now you can use
$result = $value ?? $anotherValue;

In PHP, why does "or die()" work, but "or return" doesn't?

In PHP, you can handle errors by calling or die to exit when you encounter certain errors, like this:
$handle = fopen($location, "r") or die("Couldn't get handle");
Using die() isn't a great way to handle errors. I'd rather return an error code so the parent function can decide what to do, instead of just ending the script ungracefully and displaying the error to the user.
However, PHP shows an error when I try to replace or die with or return, like this:
$handle = fopen($location, "r") or return 0;
Why does or die() work, but not or return 0?
I want to thank you for asking this question, since I had no idea that you couldn't perform an or return in PHP. I was as surprised as you when I tested it. This question gave me a good excuse to do some research and play around in PHP's internals, which was actually quite fun. However, I'm not an expert on PHP's internals, so the following is a layman's view of the PHP internals, although I think it's fairly accurate.
or return doesn't work because return isn't considered an "expression" by the language parser - simple as that.
The keyword or is defined in the PHP language as a token called T_LOGICAL_OR, and the only expression where it seems to be defined looks like this:
expr T_LOGICAL_OR { zend_do_boolean_or_begin(&$1, &$2 TSRMLS_CC); } expr { zend_do_boolean_or_end(&$$, &$1, &$4, &$2 TSRMLS_CC); }
Don't worry about the bits in the braces - that just defines how the actual "or" logic is handled. What you're left with is expr T_LOGICAL_OR expr, which just says that it's a valid expression to have an expression, followed by the T_LOGICAL_OR token, followed by another expression.
An expr is also defined by the parser, as you would expect. It can either be a r_variable, which just means that it's a variable that you're allowed to read, or an expr_without_variable, which is a fancy way of saying that an expression can be made of other expressions.
You can do or die() because the language construct die (not a function!) and its alias exit are both represented by the token T_EXIT, and T_EXIT is considered a valid expr_without_variable, whereas the return statement - token T_RETURN - is not.
Now, why is T_EXIT considered an expression but T_RETURN is not? Honestly, I have no clue. Maybe it was just a design choice made just to allow the or die() construct that you're asking about. The fact that it used to be so widely used - at least in things like tutorials, since I can't speak to a large volume of production code - seems to imply that this may have been an intentional choice. You would have to ask the language developers to know for sure.
With all of that said, this shouldn't matter. While the or die() construct seemed ubiquitous in tutorials (see above) a few years ago, it's not really recommended, since it's an example of "clever code". or die() isn't a construct of its own, but rather it's a trick which uses - some might say abuses - two side-effects of the or operator:
it is very low in the operator precedence list, which means practically every other expression will be evaluated before it is
it is a short-circuiting operator, which means that the second operand (the bit after the or) is not executed if the first operand returns TRUE, since if one operand is TRUE in an or expression, then they both are.
Some people consider this sort of trickery to be unfavourable, since it is harder for a programmer to read yet only saves a few characters of space in the source code. Since programmer time is expensive, and disk space is cheap, you can see why people don't like this.
Instead, you should be explicit with your intent by expanding your code into a full-fledged if statement:
$handle = fopen($location, "r");
if ($handle) {
// process the file
} else {
return 0;
}
You can even do the variable assignment right in the if statement. Some people still find this unreadable, but most people (myself included) disagree:
if ($handle = fopen($location, "r")) {
// process the file
} else {
return 0;
}
One last thing: it is convention that returning 0 as a status code indicates success, so you would probably want to return a different value to indicate that you couldn't open the file.
Return is fairly special - it cannot be anything like a function since it's a tool to exit functions. Imagine this:
if(1==1) return(); // say what??
If it was like this, return would have to be a function that does a "double exit", leaving not just its own scope but the caller's, too. Therefore return is nothing like an expression, it simply can't work that way.
Now in theory, return could be an expression that evaluates to (say) false and then quits the function; maybe a later php version will implement this.
The same thing applies to goto which would be a charm to work as a fallback; and yes, fallbacks are necessary and often make the code readable, so if someone complains about "clever code" (which certainly is a good point) maybe php should have some "official" way to do such a thing:
connectMyDB() fallback return false;
Something like try...catch, just more to the point. And personally, I'd be a lot happier with "or" doing this job since it's working well with English grammar: "connect or report failure".
TLDR: you're absolutely right: return, goto, break - none of them works. Easy to understand why but still annoying.
I've also stumbled upon that once. All I could find was this:
https://bugs.php.net/bug.php?id=40712
Look at the comment down below:
this is not a bug
I've searched in the documentation and I think it's due to the fact that return 0 is a statement whereas die() is essentially an expression. You can't run $handle = return 0; but $handle = fun(); is valid code.
Regarding error handling I would recommend custom codes or using custom handlers and triggers. The latter are described here for example.

Zend comparison operation style

This may not be an important issue but it bugs me anytime(quite often) I come across it, so I need to put my mind to rest. Please bear with me.
I am more used to seeing and using comparison operations like this:
if($some_var ==NULL){}
But Zend documentation(and only in zend do I notice this) always reverses the operands:
if(NULL ==$some_var){}
I'm not a computer scientist, so I would like to know if the order of these operands matter. Is there a difference or reason why zend documentation chooses the reverse style?
The result is the same. The advantage of this approach is what happens if the programmer accidentally types one equals instead of two:
if ($some_var = NULL) // this will perform an assignment instead of a comparison
if (NULL = $some_var) // this will give you a parse error
so it helps prevent those kinds of coding mistakes.
I prefer to use the Zend style for one reason. If you accidentally type = instead of == or === you will get an error. In the variable-first format, you will silently assign that value to your variable.

PHP: Condition Format - (6 == $var) or ($var == 6)?

I was browsing these PHP Coding Guidelines (a bit outdated but very interesting), and found this:
Condition Format
Always put the constant on the left hand side of an
equality/inequality comparison. For example: if ( 6 == $errorNum ) ...
One reason is that if you leave out one of the = signs, the parser
will find the error for you. A second reason is that it puts the value
you are looking for right up front where you can find it instead of
buried at the end of your expression. It takes a little time to get
used to this format, but then it really gets useful.
I have been using ($var == 6) for years now and the idea of putting them the other way around is horrifying. But as mentioned, this takes a bit time to get used to and is supposed to have clear benefits. We are just writing up standard at our company so if we want to change this, this is the moment to do that. But I'd like to hear if other have experience with this particular format. Any opinions?
EDIT
I am interested in people's experience with making this switch. To me, and most likely to others, this looks like a big change that you need to get used to. But it looks interesting. So the question to those who have switched: can you recommend this change?
6 == $var has a real advantage that $var == 6 does not. There is nothing horrifying about it at all, it just looks different. You should get used to it and use it. In fact, I haven't gotten used to it yet and I forget about it frequently. You really have to think about it and use it since the opposite is so common.
The advantage, in case you didn't know, is to prevent simple syntactical mistakes, thus:
if ($var = 6) {} //weird semantic error
if (6 = $var) {} //parse error

Is #$array['possibly_missing_key'] an anti-pattern?

Is it OK to use # when extracting a possibly missing value from a PHP array? Example:
$value = #$array['possibly_missing_key'];
The intended behavior:
if (isset($array['possibly_missing_key'])) {
$value = $array['possibly_missing_key'];
} else {
$value = null;
}
I want to know, before spreading the usage pattern.
The # operator suppresses error messages, and using it potentially sets up your code for other errors and unexpected behavior that end up hard to track down. Thus it's most certainly an antipattern.
Thus, I would very much prefer the second bit. It makes it much clearer
that it may not be present in the array, and
what the default value is if it's not present
To make it more concise you can use the ternary conditional operator ?:, as seen in Mark Baker's answer. Slightly less code and more symbols but the meaning is well-recognized.
Actually the isset variation is the anti-pattern. If you just use isset($var)?$var:NULL with the intention to suppress the "error", then you've achieved nothing over using the proper syntax for suppressing errors. It has the same outcome, yet is less readable.
People are arguing for that because of perceived "cleanliness" and because using isset is a micro optimization. Avoiding # and using isset as syntactic salt replacement is just cargo cult programming.
Or
$value = (isset($array['possibly_missing_key'])) ? $array['possibly_missing_key']: null;
Ignoring warnings is definitely an antipattern; so yes, it's an anti-pattern (and I can guarantee that if you learn to suppress warnings, one of them will come back and bite you in the posterior, if not worse).
Also, while the second version is more verbose, it gives the uninitialized variable a known state (or can be used to handle the problem, if the variable is supposed to be filled).
The third option:
$value = (isset($array['key']) ? $array['key'] : null);
I know this doesn't directly answer the question; I would have put it as a comment, except it really needed to be formatted.
The idea here is that if you're trying to make your code shorter by using a one-liner instead of an if-else block, then you can still get it into a succinct one-liner using a ternary operator, giving you the best of both worlds.
The second block of code (or Mark Baker's alternative which will work exactly the same) is better. I'm not entirely sure about PHP, but in many other programming languages, to simply ignore a variable would almost definitely throw an error. At least with the second block you are initializing the variable to some value or memory location.
Error suppression should be more commonly used if you expect a function to throw an expected error in the end-product (however, much of the time this will not be the case).
Good luck!
Dennis M.

Categories