I would have expected $x->p never to be resolved as the first condition !$x=getIt() is true, yet this is not the case for the first two examples.
When are parenthesis required in IF clause?
<?php
if(!$x=getIt() || ($x->p) ){echo('yes1');}
else {echo('no1');}
if(!$x=getIt() || $x->p ){echo('yes2');}
else {echo('no2');}
if(!($x=getIt()) || ($x->p) ){echo('yes3');}
else {echo('no3');}
if(!($x=getIt()) || $x->p ){echo('yes4');}
else {echo('no4');}
function getIt(){return false;}
?>
OUTPUT
Notice: Undefined variable: x in /var/www/html/test.php on line 3
Notice: Trying to get property of non-object in /var/www/html/test.php on line 3
yes1
Notice: Trying to get property of non-object in /var/www/html/test.php on line 6
yes2yes3yes4
The logical operator || has higher precedence than the assignment operator =. So
!$x = getIt() || $x->p
is treated like:
!$x = (getIt() || $x->p)
When getIt() returns a falsy value, this will access the property of $x before the variable is assigned, and before the result is inverted by !.
You need parentheses to override this precedence. You could also use or instead of ||, because it has lower precedence.
if (!$x = getIt() or $x->p)
I'd say that it is good habit to always use it. You definitely will thank yourself as soon as you get into using languages with preprocessor.
I use the braces for the following reason
They reduce the work required to understand the code.
They provide confirmation of the developer's intent.
As said by Marcin, it is a good habit to use them always.
But in php, if the the IF statement body is single line, then it is not necessary to use parenthesis. See below example:
if(your condition)
some php code here;
The above example is fine and will work.
Now if the body of IF statement has multiple lines of code, then you have to use parenthesis. Check below example.
if(your condition) {
some php code here;
some more code here;
....
}
Now in above case, parenthesis are required.
If parenthesis are not used in above, you wont get your expected results or you will get an error.
Thanks
Notice is no error.
The first notice says variable x is not declared (So you never assigned it before)
The others just inform you nicely that $x->p does nothing, because $x is no object and therefore has no properties
For the brackets question see other answers
Related
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.
I want to check if a numeric variable has a value (including '0') and is not empty. Empty meaning EMPTY (''), not '0'.
Is this really the best I can do with PHP?
if (isset($variable) && $variable !== '') { ... }
I'd like to do this with one check without writing a function for it...
What you are trying to check is string length, not "empty". This can easily be done using strlen().
if (isset($variable) && strlen($variable) > 0) {
// Do something
}
If you want to exclude whitespace as invalid, you can add a trim() in there as well (generally recommended).
if (isset($variable) && strlen(trim($variable)) > 0 } {
// ...
}
The best thing you could do, is making your own custom function. The point is to pass the variables by reference to not trigger a warning, when you pass an undefined variable. As posted as comment, I'd use something along the line isset($variable) AND !empty($variable) AND !is_numeric($variable) AND $variable !== false to cover all cases.
Your custom function could look like this (improved version):
function is_blank(&$variable) {
return (bool) !(isset($variable) AND (!empty($variable) OR is_numeric($variable) OR $variable === false));
}
https://3v4l.org/ZcCDu
Yes, your way is the best (most efficient) way to:
insure the variable has been set (so you don't get an warning checking a variable that's not been set)
it's not the empty string ''
But, could be '0', 0,false, null, or [] which all count as empty in php, but you wish to consider as non-empty as indicated by your OP
your !== will ensure only exactly the string '' is compared (no casting/conversion)
The use of strlen works as well, but if you look at the opcode generated you'll see direct comparison is more 3 times computationally more efficient (assuming all operations are equally weighted, even more efficient if operations like DO_FCALL take significantly more cycles to execute than a basic IS_NOT_IDENTICAL check)
The !== ''version bytecode:
IS_NOT_IDENTICAL ~1 !0, ''
The strlen() > 0 version bytecode:
SEND_VAR !0
DO_FCALL 1 $1 'strlen'
IS_SMALLER ~2 $1, 0
(The answer has been edited. Consult the additionals further down under "ternary operations").
Why go through the trouble of using all that?
Just use an "not empty" if(!empty($var)){...}
However, if you're using this with a GET array, then yes; it would be best to use an isset() and empty() on a conditional statement.
I want to check if a variable has a value (including '0') and is not empty
That to me interprets as:
Check if a value has a value and is not empty (as you wrote) and stands to contain a 0 (zero).
Therefore:
if(!empty($var) && $var='0'){...}
I'd like to do this with one check without writing a function for it...
Use a ternary operator then.
However "without a function"... right well you can't. You still need "some type of function".
About that "ternary operator" I mentioned above. You can reference what are called "nested ternary operations" in both these Q&A's on Stack:
How to concatenate multiple ternary operator in PHP?
nested php ternary trouble: ternary output != if - else
That way you won't need a custom function.
Sidenote: I am by far not taking away or trying to take away from (Charlotte's) accepted answer (which should remain as accepted). This is just an additional method of achieving your (ultimate) goal.
I use this if statement but sometimes $_GET['av'] is not set. When it is not set it throws an error. Is there a way around this?
if ($admin == 1 AND ($_GET['av'] == "0" OR !isset($_GET['av'])))
yes, just place the second statement first.
if ($admin == 1 AND (!isset($_GET['av']) OR $_GET['av'] == "0"))
That way, if $_GET['av'] isn't set, your code will never end up referencing it, the if-statement will be stopped at isset and the block just won't execute because of a false return value.
Also check out Demorgan's law and how it applies to if statements. That might help clarify the formatting of more complicated statements.
if(isset($_GET['tag'])) {
define("NJ_THISCATSUB","tag: ".$_GET['tag']);
}
There may be a couple of ways, none of which would really be recommended instead of what you have.
Except for omitting the {} you can't really shorten by packing it into a ternary operator (for example) if NJ_THISCATSUB is assumed to be not defined when $_GET['tag'] is unset. Stick with what you have -it is clear and readable, and correct.
// About as short as you're going to get:
// In other words, your method is fine and I don't recommend changing it.
if(isset($_GET['tag'])) define("NJ_THISCATSUB","tag: ".$_GET['tag']);
Ternary example:
However, NJ_THISCATSUB were defined as a null or empty value in absence of the $_GET['tag'], you could use a ternary:
// Define as NULL, absent $_GET['tag'] (not the same as what you have!)
define('NJ_THISCATSUB', isset($_GET['tag']) ? "tag: ".$_GET['tag'] : NULL);
This doesn't appear to be the behavior you are after though.
By short-circuit &&
You could take advantage of the logical && and to it this way, saving a couple of characters. If the left side of && is true, it proceeds to check the right side, and must evaluate the define() to do so. If the left side is FALSE, it will short circuit and not evaluate the right. Therefore this works:
isset($_GET['tag']) && define("NJ_THISCATSUB","tag: ".$_GET['tag']);
The above is kind of unconventional in PHP though (if there is a such thing as convention in PHP), and would be more at home in languages like JavaScript or Ruby. You're far more likely to encounter PHP code using the simpler if () you initially posted.
// Simple console demonstration
// Define X if $x is set:
php > $x = 123;
php > isset($x) && define('X', $x);
php > echo X;
// 123
// Define Y if $y is set (it isn't)...
php > isset($y) && define('Y', $y);
php > echo Y;
PHP Notice: Use of undefined constant Y - assumed 'Y' in php shell code on line 1
Notice: Use of undefined constant Y - assumed 'Y' in php shell code on line 1
// Oops, Y is not defined as a constant...
If you can allow a half-filled constant:
define("NJ_THISCATSUB", #"tag: $_GET[tag]");
Note that this only makes sense if may want to debug the absent input parameter later on. With isset it's gone forever, with #() you can bring notices back.
Also note that absent array key quotes are only permissable in double quoted string context.
In a piece of code I found the following conditional statement:
if ( !defined('MY_CONSTANT') || MY_CONSTANT !== false )
and I am wondering what this may achieve that is not achieved by simply stating:
if ( MY_CONSTANT !== false )
..
is it not so, that in case MY_CONSTANT !== false then it MUST also be defined, making the first argument of the first example superfluous, or am I missing something?
If the constant may be undefined at that point, trying to access it will produce a warning on properly configured servers. You don't want those filling up your error logs, hence the defined() check.
The or conditional stops evaluating as soon as one of the conditions is true.
Since the conditions are evaluated left to right, and trying to check an undefined constant yelds an exception, you first check if it is defined, and then for its value.
If the constant is not defined, the if statement exits, and doesn't try to check the value.
Your version and the first version are not the same:
If it is not defined, the first condition of the first version will be true, and it will 'trigger'.
If it is not defined, your version will be false. (well, at least raise an error ;) )
no, because if MY_CONSTANT is not defined, PHP will give you an error message :
Notice: Use of undefined constant MY_CONSTANT
If MY_CONSTANT is not defined, PHP will do two things:
Log and/or display an error when you try to use it
Interpret MY_CONSTANT as if it were the literal string "MY_CONSTANT"