PHP && operators - php

Just curious why this would trigger a warning.
Note: query string param "test" is not included in the URL
//Notice: Undefined index: test
if($_GET['test'] === 'somestring' && !empty($_GET['test'])) {
}
//Valid - No Warning. Why is this Valid? Param 'test' was never given
if(!empty($_GET['test']) && $_GET['test'] === 'somestring') {
}
Is this because PHP evaluates from LEFT to RIGHT? And not the whole condition?

if(!empty($_GET['test']) && $_GET['test'] === 'somestring') {
Because you're using &&, if any condition is false, further conditions are not checked. Conditions are checked in the order they're written. Since here, first condition !empty($_GET['test']) is false, the next one does not evaluate hence no warning.

In the first example:
//Notice: Undefined index: test
if($_GET['test'] === 'somestring' && !empty($_GET['test'])) {
}
you are trying to access the value of the variable first, before checking if it exists, which is what the second example is basically doing. After checking that it does not exist, it exits the conditional without testing the second part.

Simply put, it comes down to operator precedence.
The documentation shows that && is evaluated left-to-right, which means the left part of the clause is evaluated first. In your case, that clause results in a warning. If you reversed your clause order, the empty() check would return false, then the logic would short circuit and stop evaluating.

Related

How does PHP evaluate compound if statements?

Given the nested if statements below:
if(file_exists($fullPathToSomeFile)) {
if(is_readable($fullPathToSomeFile)) {
include($fullPathToSomeFile);
}
}
how does this differ from:
if(file_exists($fullPathToSomeFile) && is_readable($fullPathToSomeFile)) {
include($fullPathToSomeFile);
}
Specifically, I want to know how PHP will treat is_readable() if $fullPathToSomeFile does not exist (first conditional fails).
At some point, I started nesting these because using the one-liner version was throwing errors under some conditions. It seems to me that using any 'and' will ask PHP to evaluate everything regardless of the true / false result.
What I really want is to have it stop evaluating when it reaches the first false, thereby preventing warnings or fatal errors when the conditional fails. Doing it nested (first example) guarantees this, but nested if statements are harder to read and maintain.
What's the current best practice for handling this?
Specifically, I want to know how PHP will treat is_readable() if $fullPathToSomeFile does not exist (first conditional fails).
PHP uses short-circuit evaluation for the && operator. That is, if the first condition in an expression like if (A && B) fails, it is obvious the the whole condition will be false. Thus, the second condition B does not need to be evaluated to determine the result and will not be evaluated at all.
Take for example the following code:
<?php
function hey()
{
echo "Hey there!\n";
return true;
}
if (false && hey())
{
echo "Statement evaluated to true.\n";
}
else
{
echo "Statement evaluated to false.\n";
}
?>
This will echo only one line ("Statement evaluated to false."), but not "Hey there!", because the second part of the if condition will not be evaluated.

Will an If Statement Stop Checking if the first OR condition is met in PHP?

I want to try and make my code as efficient as possible and from what ive read
if($process == true)
Will process faster than something that calls a function. I.e
if(count($total) == 100)
So if i had an OR inside my if and the first condition was a simple boolean check and it turned out to be true would the second part of the condition still be checked anyway?
For example
$process = true;
if($process == true || count($total) == 100)
Would the count function still be called even though process is true and that is enough the make the condition pass.
PHP has indeed a mechanic named short-circuit:
http://php.net/manual/en/language.operators.logical.php#example-140
If the first operand of a logical OR is true, then the second part isn't evaluated, and the function isn't called.
Since comparing a variable to a boolean is faster than calling a function in PHP, this mechanic can help you to optimize, but never forget that premature optimisation is the root of all evil.
It will work same as exactly logical operator works. For example foo() will never get called.
if (false && foo()) {
}
if (true || foo()) {
}
In case of OR once it found a true statement it wont check further conditions,
In case of AND once it found a false statement it wont check further conditions.
its known as lazy evaluation.
illustration:
<?php
$var=0;
if($var++ || $var++){//Since 0 means false in Php both conditions will be checked
//Do nothing
}
echo $var;//output :2
if we change condition to if(++$var || $var++) the first condition will return true hence next condition will not be checked thus it will print output as 1;
If any statement inside a or is true other statements will not be checked and the if will be evaluated to true.
If you are checking a and statement all statements needs to evaluate to true and if any of them is false the stamen check will stop because the if is already false.
Just another important detail is that a function inside a if does not slow down the if check, what will slow down is what the function is doing and if it needs a lot of processing of course will be slower than just check a boolean but do not get afraid of use functions because they are very important in any system.
(I remember this from C# but I'm quite sure it's the same in php)
This depends if you use the single | or double || I think if you used the single ones it would still go do the other one ( usefull for when theres a function like loggin behind it ) if you use double and the first one is true it'll skip the second condition.
(This could be the other way around, so best bet is to try it using Javascript eg. create 2 function each returning true after alerting something, and thest these with either 1 line or 2)

Whats the difference in these two php conditions?

i am trying to check whther $_GET['id'] is set and is numeric else killing the code execution.,
following both codes are working for me , but would like to know whats the difference in between them ?
php condition 1
<?php
if(!isset($_GET['id']) || (isset($_GET['id']) && !is_numeric($_GET['id']))) {
die();
}
php condition 2
<?php
if(!isset($_GET['id']) || !is_numeric($_GET['id'])) {
die();
}
The difference is that the first one has an unnecessary extra check if $_GET['id'] is set. PHP uses what is called short-circuit boolean evaluation, which means that if the left side of an || is true, the right side doesn't need to be evaluated. So, even in the second example, !is_numeric($_GET['id']) will never get evaluated unless isset($_GET['id']) is true.
Logically these statements are equivalent.
You're basically doing
A || (!A && B)
if A is true, then the rest won't be executed.
If A is false, !A will be true anyway. So the !A is redundant.
Functionally they are the same, but in practice, you don't need the extra condition.
You can see the logical explanation here:
In the first one
It makes three checks which are unnecessary.
In the second it won't catch one of the conditions required
|| means OR - either one of the conditions should evaluate to true
&& means AND - both conditions must be true
To work properly you need this
if (!isset($_GET['id']) && !is_numeric[$_GET['id']])
die();
The first statement does the same thing but it check if $_GET['id'] is set two times which isn't needed.

PHP conditional statement using $_SESSION assigns value, but why?

I actually found out how to solve this particular problem on my own, but it's still driving me crazy wondering why the problem came about to begin with. I had a conditional statement:
if($_SESSION['authenticated'] = 1) {
DOSTUFF;
}
Now prior to this if statement I know that $_SESSION['authenticated'] is empty by using print_r(). However, after executing this code block this conditional statement assigns 1 to $_SESSION['authenticated'], which makes the if statement evaluate to true no matter what! I found a way around this using isset(), but I still have no clue why a conditional statement would assign a value to a variable in the first place when it should only evaluate whether or not the condition is true or false.
Because = is assignment. You want == or === which test for equality. === checks that the operands are both equal and of the same type. == only checks for equality.
You have a semantic (or syntactic) (or typing) error. You should use double equal sign for equality comparison like this:
if($_SESSION['authenticated'] == 1) {
DOSTUFF;
}
If you use single equality sing, that means assignment, and the assigned value gets evaluated in the if statement.

More logical "if $var is defined and $var does not equal" statement in php

In PHP, I have the if statement:
FIX_RECIPE_ID && FIX_RECIPE_ID != $favouriteRecipeId
It does what it says on the tin, though, is there a more logical way of writing this statement?
Thanks all in advance!
If FIX_RECIPE_ID is a constant, use this syntax.
defined(FIX_RECIPE_ID) && (FIX_RECIPE_ID != $favouriteRecipeId)
If not, make it a variable first, then use
isset($FIX_RECIPE_ID) && ($FIX_RECIPE_ID != $favouriteRecipeId)
Sorry to submit as an answer, but I don't have commenting privileges yet I guess.
Shiplu's answer is not completely correct. The line:
defined(FIX_RECIPE_ID) && (FIX_RECIPE_ID != $favouriteRecipeId)
Will appear to work, but will throw a notice along the lines of Use of undefined constant FIX_RECIPE_ID - assumed 'FIX_RECIPE_ID' if it's not defined, and will have very unexpected behaviour (typically returning false) if it is.
The defined function takes the name of the constant as a string. PHP will assume you mean the string 'FIX_RECIPE_ID' if it's not defined and work as expected (although, as mentioned, throwing a notice). If it is defined, you'll be checking whether a constant exists named after the value of FIX_RECIPE_ID.
Meaning when it's not defined, your check is effectively:
defined('FIX_RECIPE_ID') && (FIX_RECIPE_ID != $favouriteRecipeId)
Which is correct and will return false. When it is defined, however, (let's pretend it's 10), the check will become:
defined(10) && (FIX_RECIPE_ID != $favouriteRecipeId)
And defined will return false. This entire conditional will always return false.
The correct way to use defined in this context would be:
defined('FIX_RECIPE_ID') && (FIX_RECIPE_ID != $favouriteRecipeId)

Categories