PHP shorthand logical operators AND and OR [duplicate] - php

This question already has answers here:
Closed 11 years ago.
Possible Duplicates:
PHP - and / or keywords
PHP shorthand syntax
Quick question. I keep seeing shorthand expressions in libraries around the place, and despite having been a PHP developer for over 3 years, I struggle to quite see how the following would evaluate.
What exactly does the PHP interpreter do with the following shorthand lines of code when it encounters them?
<?php
defined('foo') OR exit('foo is not defined!');
$foo AND $this->bar();
I'm guessing that it' obviously conditional execution - i.e. the second statement won't get executed unless the first bit is true... but the use of the bitwise operators confuse me a bit.
Can someone elaborate?
Thanks :)

I believe that this is a form of short-circuit evaluation: http://en.wikipedia.org/wiki/Short-circuit_evaluation
Essentially, when evaluating an entire expression, the interpreter short circuits once it is certain of the result. For example:
true OR do_something();
This expression never calls do_something() because the first operand of OR is true, so the entire expression must be true.

Back when I was learning PHP I remember reading the 'do or die' style commands and not fully understanding them at the time, the classic example is:
mysql_connect() or die('couldn\'t connect');
Bear in mind that the conditions will only run if they're required, for example:
if (a == b && b == c)
Here b == c will only be tested if a == b. The same theory applies to or:
if (a == b || b == c)
Now b == c will only be tested if a != b.
In this case you are relying on this order to run a command (exit or $this->bar()) in certain conditions.
Be Aware... exit() is a bad idea in this circumstance - if you exit('something went wrong') there's nothing anyone can do to hide this error from the user, also it's likely to issue a 200 OK HTTP status where a 500 Internal Server Error would be much more appropriate, I would consider something more like:
defined('foo') OR throw new Exception('foo is not defined!');
Here you have a chance to either catch the Exception or at least let PHP catch it and issue a 500 status.
Mat

Much less elaborate than you think. The or keyword is the same as ||, except it has lower precedence. See the corresponding PHP page for details.
The actual execution of this statement relies on a separate concept involving logical operators: short circuiting. This means that, in the case of or, the second statement is not evaluated if the first statement turns out to be true. (Since in a conditional, for instance, the entire condition would return true without ever needing to see the second half.)

Sometimes you have a function that looks something like:
function test()
{
$foo = TRUE;
$bar = FALSE;
return $foo && $bar;
}
In this case, if some does:
$bla = test();
if($bla) {
... do something
}
The "...do something" will not get executed, because the function as a whole returned false.
return $foo && $bar means that both variables have to be true in order for the function to return true.
On the other hand, if it stated: return $foo || $bar; then the function would return true, because at least one variable is true.

Related

Why use an extra set of parenthesis when using PHP boolean test in an IF()?

I'm sorry the title of this question is odd. I couldn't find a good way to word it!
The idea is simple, sometimes you see PHP tests this way:
if (!a_function("something")) { }
Here you can think of it as "if not true". I sometimes see the exact same thing but with extra parenz:
if (!(a_function("something"))) { }
Why does it require the extra parenz after the bang? Don't they both essentially mean if (!true)?
For extra bonus, what are the reasons for the two styles (does this have a name?) and maybe give examples of how they would give alternate results if not used correctly.
update:
Here is an example in a PHP script I'm using, the author is testing environment variables and seems to use the styles interchangeably:
if (!(extension_loaded("iconv"))) { ... }
if (!(extension_loaded("xml"))) { ... }
if (!function_exists("json_encode")) { ... }
if (!ini_get("short_open_tag")) { ... }
I know you can't answer for the programmer here, but why would they be alternating the use of extra parenz when these small functions are right next to each other?
I happen to know that, for example, the return value of ini_get is just the number 1, and the return value of the extension_loaded functions may also just be the number 1, so it seems like there would be no difference. I'm not 100% sure there isn't some other trick to this than simple preference or order of operation.
update 2:
I understand parenz can be used for either clarity, or order of operations, but I'm not convinced it is only personal preference beyond that.
In my example above, everything depends on what is returned by the functions that are being tested.
It's my understanding that by wrapping a statement in parenz, PHP will force it into a bool. But when it's not in parenz, could there be a return value that breaks the code without using the parenz around it to force a bool?
If people say, in my example code above, that there is nothing but personal preference going on, then I'll just have to accept that, but I have my doubts.
the parenthesizes are used in case if there are more than 1 logical operator with different precedence, to indicate that "!" operator must be applied after all other operators have been processed. For example:
if(!($var1 < $var2))
First will be checked if $var1 is less than $var2, and after that will be checked if the result is false.
If use that:
if(!$var1 < $var2)
then firstly will be checked if $var1 is false and the result will be compared to $var2, that simply do not make sense.
It's not required. It's a matter of personal preference. Sometimes you like to have extra parens to be EXTRA certain of how the expression will be evaluated.
if(a or b and c)
is confusing.
if ((a or b) and c)
is much more clear.
if(a or (b and c))
is much more clear.
They both work, but some people might have different opinions on which one is more readable.
Parenthesis are not required in the given case, but they can be if, for example, you also assign a variable at the same time :
if (($myVar = myFunc()) !== false) {
// Doing something with $myVar, ONLY if $var is not false
}
While, in the following case, it will change the logic
if ($myVar = myFunc() !== false) {
// Here $myVar = true or false instead of the wanted value
}
if( !(should_return_trueA() && should_return_trueB())) {
// at least one have returned false
}
esentially is the same as:
if( !should_return_trueA() || !should_return_trueB() ) {
// at least one have returned false
}
It's, in my case, a practice to avoid mistaken/ommited exclamation marks. Useful, when building more complex conditions and looking for all-false or all-true result.

Consecutive if-conditions in PHP [duplicate]

This question already has answers here:
Does PHP have short-circuit evaluation?
(8 answers)
Closed 8 years ago.
If you have two consecutive conditions in PHP, do they both get evaluated, or is the if-case evaluation cancelled if the first condition already failed (so the result of the second condition wouldn't matter)?
if (condition1 && condition2) { }
PHP uses Short Circuit Evaluation, so the second condition would not even be evaluated if the first one is false.
Since you are using &&, if the left condition fail the right ones wont be evaluated
if (statement1 && statement2)
{
//If the left part is false, the right part is not even checked
}
if (statement1 || statement2)
{
//if the left part is false, the right part is checked
}
If the result of the first condition makes evaluating the second condition unnecessary, PHP won't evaluate it (the second condition). This is called Short-circuit evaluation, a term that is also meantioned in PHP's documentation on logical operators.
Here is a small example to prove it:
<?php
function foo() {
echo 'Bar';
return true;
}
if (false && foo()) { }
Because PHP uses Short-circuit evaluation, foo() will not be executed, and therefore Bar will not be printed on the screen.
Because 'Test' will never be echoed, you can conclude that if the first condition returns false, the second condition is never evaluated.
The same works for || (OR) operators, but the other way around:
<?php
function foo() {
echo 'Bar';
return true;
}
if (true || foo()) { }
Since the first condition is already true, there is no need to evaluate the second one. Again, foo() is not executed, so you'll get an empty screen.
Its an AND. And PHP is lazy as hell. If the first functions returns false, it will not touch the other functions. Its the same with OR. If you use it, PHP is lazy and only evaluates as long as necessary.
if(condition1() || condition2())
If condition1() returns true, condition2 will be untouched. Its nice to know for performance, always evaluate the fast functions first in that case.^^

Replacing IF with a logical expression in PHP

I was refactoring some old code when I stumbled upon a construct similar to this:
// function bar() returns a value
// if the value is an instance of customException class, terminate with error code
// else process the regular data
$foo = bar();
checkForException($foo) && exit($foo->errorCode());
process($foo);
Now strange as it might seem, this is a lot shorter then
$foo=bar();
if(checkForException($foo)) {
exit($foo->errorCode();
}
else {
process($foo);
}
And somewhat more readable (at least after the initial surprise) then
$foo=bar();
(checkForException($foo)) ? exit($foo->errorCode()) : process($foo);
While shorter code doesn't necessarily mean more readable code, I find this to be somewhere in the middle of the two "standard" ways above.
In other words, instead of
if($foo) {
bar();
}
else {
// there is no real reason for this to exist, since
// I have nothing to write here, but I want to conform
// to the general coding practices and my coding OCD
}
One could simply write
$foo && bar();
So what is the reasoning behind this not seeing much use? Can it be as simple as "Don't reinvent the wheel, write the more readable if/else, and if you really want to shorten it, that's what ternary operator is for"?
EDIT: Please keep in mind that the above code was quickly derived from the original code and was mean to be just an example of the use of "short circuit" code. If you can, please restrain from suggesting code improvements, since that was not the desired outcome of the question.
Example No.2
userCheckedTheBox($user) && displayAppropriateInfo();
While $foo && bar(); is fewer lines of code it's much less readable. Making your code easy to understand is usually more important than reducing the total LoC. Even if it's you're not working in an environment with multiple programmers, you will have to come back and read your code at some point in the future, and you probably won't be able to remember what the rationale was behind every line of code (Eagleson's Law).
Generally, you should limit the use of these kinds of statements to only those cases where the programmer's intent is absolutely clear. In my opinion, it's very bad practice to have code which tests a condition and code which actively modifies the current state of the program on the same statement.
Here's one acceptable use for this kind of code:
$isValidUser = $userName && usernameIsValid();
Here, both sides of the && operator are testing a condition, the fact that the right side is calling a function to do that does not harm the readability of the code.
There's an old technique which I believe was popular in hacked-together perl scripts to show errors. pseudo-code:
myFunction( ) || exitWithError( "Uh-oh" )
When coding-to-a-deadline, and when the user interface doesn't need to be stellar, it's a quick way to avoid errors.
The style is also popular in javascript for default parameters:
function myfunction(foo) {
foo = foo || 0;
// note that a non-zero default won't work so well,
// because the user could call the function with 0
}
and for null-checks:
var bar = foo && foo.property;
I find that once you're used to it, it's very readable and often more intuitive than if/else or ?:. But you should only use it when it makes sense. Using it everywhere is going to get very confusing. For example, in your example, you should not use it. Personally I use it for simple error checking and some default values. In big projects, you almost always want to do a lot more when an error occurs, so in those cases you shouldn't use this.
Also you should be careful; this only works in languages which have short-circuit evaluation (http://en.wikipedia.org/wiki/Short-circuit_evaluation). And sometimes and and or are short-circuit, while && and || are not.
myfunction() or die("I'm melting!"); is also quite satisfying to write.
Finally, empty else blocks as a rule is something I've never seen before, or heard anyone recommend. It seems very pointless to me. The most readable option for your example is, quite simply:
if( $foo ) {
bar( );
}
For errors you should use real exceptions:
try {
$foo = bar();
} catch(FooException $e) {
exit($e->errorCode);
}
process($foo);
See the documentation for errorhandling.
What ever that code is doing, returning an instance of CustomException just doesn't add up. Why not change the function definition a little:
function bar()
{
$stuff = true;
if ($stuff === true)
{
return 'Value on success';
}
//something went wrong:
throw new CustomException('You messed up');
}
try
{//here's the outlandish try-catch block
$foo = bar();
}
catch (CustomException $e)
{
exit($e->message());//fugly exit call, work on this, too
}
//carry on here, no exception was thrown
Also, calling that second function (checkForException($foo)) is just absurd. Function calls are cheap, but not free. You want to know if the function returned an instance of CustomException? Don't turn that into a function, but use instanceof. Using short-circuit to keep the number of chars (ad thus parse-time) down, while at the same time wasting resources on on all other levels is about as silly as turning up in a V8 mustang on a hyper-miling course.
Another possible Solution for your problem:
$foo = bar();
!checkForException($foo) or exit($foo->errorCode);
process($foo);
But better change !checkForException for isNoException or something along those lines.

Processing of php 'if x && y'

I was wondering how php processes if statements.
If i were to have something such as:
if (isset($_GET['foo']) && $_GET['foo'] != $bar)
If foo isn't set, would it then drop out of the if straight away (as it is an 'and' statement so it can't succeed anyway) or would it also check the second part, rather pointlessly?
What you're describing is known as "short-circuit evaluation".
Most languages work this way, including PHP, so they will evaluate an expression until they are certain of the result, and then stop, so the remainder of the expression would not be evaluated.
As you say, this is the most efficient approach.
However, it can potentially throw a spanner in the works for inexperienced programmers, who nay try something like this:
if(doFirstProcess() && doSecondProcess() {
print "both processes succeeded";
}
In this case, the programmer is expecting both functions to be called, but if the first one returns false, then the second one will not be executed, as the program already knows enough to be certain of the final result of the expression, so it short-circuits the remainder of the expression.
There are a few languages which don't do short-circuit evaluation. VB6 was one example (back in the day). I don't know about VB.Net, but since it's evolved from VB6, I would suspect it would be similar. But aside from that, all other languages that I've worked with have used short-circuit evaluation, including PHP.
There is a section in the PHP manual about this here: http://www.php.net/manual/en/language.operators.logical.php
And you can read more on short circuit evalution here: http://en.wikipedia.org/wiki/Short-circuit_evaluation
Hope that helps.
It's known as short-circuit:
&& and and operators is executed from left to side
If left side is considered false, no reasons to check right side, so it's omitted, false returned
|| and or operators is executed from left to side too
If left side is considered true, no reasons to check right side, so it's omitted, true returned
Manual example:
// foo() will never get called as those operators are short-circuit
$a = (false && foo());
$b = (true || foo());
$c = (false and foo());
$d = (true or foo());
it will leave the if statement after the first expression evaluates to false because this statement can never be true if the first one is false and they are combinded via AND
you can check this very easily. If it wouldn't be like I said, you would get a notice that $_GET['foo'] is not defined
If the first part is false, it stops the if.
Certain operators, most notably && and || are so-called short-circuit operators, meaning that if the result of the operation is clear from the first operand (false or true, respectively), the second operand does not get evaluated.
Edit: Additionally, operands are guaranteed to be evaluated in order, this is not always true of other operators.
Will go out after the first statement.
you can test it:
will print 1:
if(1==1 && $a=1 == 1){
}
print $a;
Will not print a thing:
if(1==2 && $a=1 == 1){
}
print $a;
&& does short-circuit (i.e. returns false as soon as one condition fails).
If it doesn't, then having the isset would be pointless — it exists to prevent errors when trying to compare an undefined value to a string.
If the first check if (isset($_GET['foo']) returns false, the second part will not even be looked into anymore.

Ternary operators and variable reassignment in PHP

I've perused the questions on ternary operators vs. if/else structures, and while I understand that under normal circumstances there is no performance loss/gain in using ternary operators over if/else structures, I've not seen any mention of this situation. Language specific to PHP (but any language agnostic details are welcome) does the interpreter reassign values in situations like this:
$foo = 'bar'
$foo = strlen($foo) > 3 ? substr($foo, 0, 3) : $foo;
Since this would evaluate to $foo = $foo; is this inefficient, or does the interpreter simply overlook/discard this evaluation?
On a side note, what about:
!defined('SECURE') ? exit : null;
I don't know if your first example is inefficient, but it sure is pointless. I still think an if statement is clearer:
$foo = 'bar';
if (strlen($foo) > 3)
$foo = substr($foo, 0, 3);
And while the following works, it makes no sense to place null at the end because a ternary operator is meant to be used to evaluate expressions/values, but here null does nothing other than to prevent a parse error:
!defined('SECURE') ? exit : null;
More commonly, you would see this, an example of boolean short-circuiting (or exit doesn't execute if SECURE is not defined, because the or conditional expression evaluates to true automatically once at least one condition is found to be true):
defined('SECURE') or exit;
The point I'm trying to make is this: don't use ternary conditional expressions just because you can.
In this cases, I use the form presented by BoltClock:
if (strlen($foo) > 3) {
$foo = substr($foo, 0, 3);
}
PHP does not implement something more simple to work in this cases, yet :/
The topic that using a ternary here is not optimal has already been covered above. I'm going to address your question about whether it will reassign the value:
This depends on what you call "reassigning". PHP does not optimize, so the $foo = $foo will be evaluated. On the other hand this will not cause PHP to copy the value of $foo to a new chunk of memory. Probably PHP will just increase the refcount on $foo and then immediately decrease it (though I'm not sure about the exact implementation details of self-assignment). So, even though PHP will execute the statement, it won't affect performance (unless you choose to write $foo = $foo seven million times in your code).
There is always short-circuiting, although as #BoltClock said, an if statement is probably more readable in my opinion, and opens the door to else if and else conditions as well.
strlen($foo) > 3 && $foo = substr($foo, 0, 3);
The latter statement will only be executed if the former evaluates to TRUE.

Categories