Multiple conditions in the ternary operator safe? - php

I have seen advice that says the ternary operator must not be nested.
I have tested the code below and it works okay. My question is, I haven't seen the ternary operator used like this before. So, is this as reliable as it were used in an if or could something like this come and bite me later(not in terms or readability, but by failing).
$rule1 = true;
$rule2 = false;
$rule3 = true;
$res = (($rule1 == true) && ($rule2 == false) && ($rule3 == true)) ? true : false;
if($res) {
echo "good";
} else {
echo "fail";
}
Thanks!

If the results you are returning from the ternary operator are only "true" and "false", then you don't even need the operator. You can just have:
$res = (($rule1 === true) && ($rule2 === false) && ($rule3 === true))
But, to answer your question, yes multiple conditions work perfectly well.

It's totally legal, it works and is "as reliable as if", but it looks ugly.
If you put each ternary statement inside parenthesis, nesting would be fine too:
$res = ( $rule1 ? true : ( $rule2 ? true : false ) )
The only thing that is advised against in the manual is nesting without parenthesis like this:
$res = ( $rule1 ? true : $rule2 ? true : false )

Is there a reason you want to have your conditions saved into a variable? this is the simplified version of above.
if($rule1 && !$rule2 && $rule3)
{
echo "good";
}
else
{
echo "bad";
}

You do not need the ternary if you are going to return true or false. Quoting the manual:
The expression (expr1) ? (expr2) : (expr3) evaluates to expr2 if expr1 evaluates to TRUE, and expr3 if expr1 evaluates to FALSE.
This means
$res = (($rule1 == true) && ($rule2 == false) && ($rule3 == true));
will assign true or false already. Also, if dont care about $rule being booleans, you dont need the comparison with ==. You also dont need the braces, e.g.
$res = $rule1 && !$rule2 && $rule3;
is the same as your initial ternary.
A good practise when you have multiple expressions like that is to hide the actual comparison behind a meaningful method or function name, e.g.
function conditionsMet($rule1, $rule2, $rule3) {
return $rule1 && !$rule2 && $rule3;
}
and then you can do
if (conditionsMet($rule1, $rule2, $rule3)) {
// do something
}
Of course, conditionsMet isnt that meaningful. A better example would be something like isSummerTime or isEligibleForDiscount and so on. Just express what the rules express in the method name.
You might also be interested in Simplifying Conditional Expressions from the book Refactoring - Improving the design of existing code.

You can also do
$res = ($rule1 && !$rule2 && $rule3);

It's legal and doesn't have to be "ugly". I use the "hook" operator often, in table form it's quite clean, e.g.:
bool haveANeed()
{
// Condition result
// ---------- ------
return needToEat() ? true
: needToSleep() ? true
: needToStudy() ? true
: needToShop() ? true
: needToThink() ? true
: false; // no needs!
}
This function would, IMHO, be less clear and certainly longer if written with if-else logic.

Related

What does while ($variable) mean in PHP?

I am new to PHP and am currently constructing a do/while loop from a tutorial. I would understand if the whole condition was ($variable == true) or ($variable == false), however in the tutorial the while condition is simply while($variable). Could anyone explain this to me?
Here is the tutorial code.
<?php
$loopCond = false;
do {
echo "<p>The loop ran even though the loop condition is false.</p>";
} while ($loopCond);
echo "<p>Now the loop is done running.</p>";
?>
All such conditional statements, including while and if, are evaluating the given expression against true. If the expression results in true, the statement executes the action. If it results in false, it won't.
$var == true is an expression which compares $var to true. The result of this expression is either true or false. The important point to understand here is expressions. Expressions are things which return values. Try var_dump($var == true) or var_dump(4 > 6). It shows you that the expressions return a boolean value. Here:
if ($var == true)
first $var is compared to true, which yields either the value true or false, which is then evaluated by if whether it's true or false, which then prompts if to execute the following statement or not.
In other words: it's redundant.
if ($var)
This simply causes if to evaluate whether $var is true or false and then execute the following statement. The == true is essentially already "built in".
The following statements are all essentially equivalent:
if ($var)
if ($var == true)
if (($var == true) == true)
if ((($var == true)) == true) == true)
...
A boolean value true or false should not be used with a redundant $c == true as the result is the same as $c: true or false
$driving = true;
while ($driving) {
while ($driving == true) { // ugly
while (! $driving) { // while not driving.
while ($driving == false) { // ugly
$drinking = ! $driving;
if ($driving && $drinking) {
Hence also use adjectives for boolean variables.
A condition is met, if the value or statement in it is considered as true.
The code $variable == true is a statement that looks whether the value of the variable is true and if it is, yields true - Or false if it is not.
However, as this means, that $variable itself can only ultimately be true or false, you don't even need the statement, as its return value will also be one of those two.
Therefore $variable is exactly the same as $variable == true.
I hope this made it clear.
The semantic of while/do-while is
while(<boolean expression>) {
// do your stuff
}
A boolean expression is anything that evaluates to true or false. So, if $loopCount is true, then $loopCount == true is checked on every loop and evalutes to true. But you could also write $LoopCount as condition, since it also evaluates to true.
This is very handy for using other data types, e.g. integers.
$count = 0;
while ($count < 10) {
$count = $count +1;
}
Here $count < 10 is a boolean expression that evaluates to true as long as $count is not higher then 9.
A while loop runs as long as the condition is met, in other words, as long as the boolean expression you provide evaluates to true.
You can also just use a variable, e.g. $loopCount when that variable evaluates to a boolean or a constant (even the constant value true).
Like Padarom said: Therefore $variable is exactly the same as $variable == true.
In your case: The while-do loop determines if redo the loop-body after the first run. Means the loop-body is executed exactly one time regardless what value $variable has. After the first run, the while($variable) checks if the expression is true. If so, the loop-body is executed second time and so forth.
Check PHP reference for do-while loops here. PHP.net do-while reference
while ($loopCond) and while ($loopCond == true) is the same thing. It checks the "trueness" of whatever you put in the brackets.
If I ask a question "does sun set in the west ? " what would be your answer, definitely YES OR TRUE. Same as compiler always look for statement value. Take a look
$condition = true;
if($condition == true )
// above will return TRUE; in short $condition == true will replaced by true at runtime. But if we place true directly which is $condition value or can say we place $condition instead true thus statement become shorten and look like...
if($condition) {
}

why does PHP variable with assigned null value is false in if statement?

I was just debuging some code, and found that
$id = null;
$field = $id === null ? true : false;
$field = $id ? true : false;
Both should set $field to TRUE value. However for some reason it does not work as intended. First one returns true, other one returns false.
Edit1: I accidentaly mistook things when writing question. It should be why its different.
Edit2: I ask my question since this behaviour is different on 2 different servers.
2nd Example is expected to return True, but somehow it does not return true on one of my servers.
Edit3: Here is the real code. Its class/ObjectModel.php in Prestashop 1.5
/* Copy the field, or the default language field if it's both required and empty */
if ((!$this->id_lang AND isset($this->{$field}[$id_language]) AND !empty($this->{$field}[$id_language]))
OR ($this->id_lang AND isset($this->$field) AND !empty($this->$field)))
$fields[$id_language][$field] = $this->id_lang === null ? pSQL($this->$field) : pSQL($this->{$field}[$id_language]);
elseif (in_array($field, $this->fieldsRequiredLang))
$fields[$id_language][$field] = $this->id_lang === null ? pSQL($this->$field) : pSQL($this->{$field}[Configuration::get('PS_LANG_DEFAULT')]);
else
$fields[$id_language][$field] = '';
The expected behaveior (that is true on most servers) is if $this->id_lang is set to null then $this->$field should be used instead of $this->$field[$id_language].
However, on my server set on CentOS machine this behaviour differ and when value is set to null it gets $this->$field[$id_language] as value.
The statement (you have unfortunately edited) is the same as:
$id = null;
if($id === null) {
$field = true;
} else {
$field = false;
}
Are you still expecting false? :)
The statement in your question is using the so called ternary operator. To understand your example you should read this documentation (Section: Ternary Operator)
The ternary operator is a shorthand for if statements that allows to shorten code, especially conditional assignments. However, the fact that you ask this question is a good example for it's disadvantage: It is less readable ;)
Regarding Edit 3, if you are experiencing different results on different distributions with the same code and data set then my guess is that the CentOS binaries you are using have been modified by their developers and a bug has been introduced, perhaps in operator precedence.
As a general rule, I personally prefer to enclose each clause or group of clauses in parentheses in order to reduce the chances of something like this happening, thus I suggest giving the following a try:
if ((!$this->id_lang && isset($this->{$field}[$id_language]) && !empty($this->{$field}[$id_language])) || ($this->id_lang && isset($this->$field) && !empty($this->$field))) {
$fields[$id_language][$field] = (($this->id_lang === null) ? pSQL($this->$field) : pSQL($this->{$field}[$id_language]));
} else if (in_array($field, $this->fieldsRequiredLang)) {
$fields[$id_language][$field] = (($this->id_lang === null) ? pSQL($this->$field) : pSQL($this->{$field}[Configuration::get('PS_LANG_DEFAULT')]));
} else {
$fields[$id_language][$field] = '';
}
This way, you force the parser to evaluate the various clauses and operators in the order you define rather than the order the parser thinks they should be processed.
Original Answer
$field is being set to true because the === operator compares two values and returns true if they contain both the same value and the same type.
By setting $id to null, you are essentially running this:
$field = (null === null);
You could expand your current code to clarify the logic as follows:
if ($id === null) {
$field = true;
} else {
$field = false;
}
Or, you could just simply run:
$field = ($id === null);

Two if statements using ternary condition

The title seems confusing but this is my first time using ternary conditions. I've read that ternary is meant to be used to make an inline if/else statement. Using no else is not possible. Is it true?
I want to change this with ternary condition for practice
if (isset($_SESSION['group']
{
if ($_SESSION['item'] == 'A')
{
echo "Right!";
}
}
It has two if statements only. The second if is nested with the other. I've also read that to make a no else possible for ternary, it just have to be set to null or empty string.
It's a bad example because you can use an AND-operator on the nested if:
$result = isset($_SESSION['group'] && $_SESSION['item'] == 'A' ? true : false;
Of course you can nest ternary operator, too:
$result = isset($_SESSION['group'] ? ( $_SESSION['item'] == 'A' ? true : false ) : false;
with echo
echo isset($_SESSION['group'] ? ( $_SESSION['item'] == 'A' ? "Right!" : "false" ) : "false";
echo (isset($_SESSION['group']) && $_SESSION['item'] == 'A') ? "Right" : ""
Better still (readable, maintainable), use:
if (isset($_SESSION['group']) && $_SESSION['item'] == 'A')
{
echo "Right!";
}
isset($_SESSION['group'] ? (if ($_SESSION['item'] == 'A') ? echo "Right" : null) : null
Try this, I think it might work =].
For further reading on ternary conditions in Java/ whatever you're using look at http://www.devdaily.com/java/edu/pj/pj010018
You can nest two ternary statements as this example:
echo (isset($_SESSION['group']))?($_SESSION['item']== 'A')?'Right!':null:null;
Did you know you can do this as well? (isset($_SESSION['group']) && ($_SESSION['item']=='A')) &&($result$c= 1); or echo (isset($_SESSION['group']) && ($_SESSION['item']=='A')) ? 'Hello!':'World!';

Shorthand conditional to define a variable based on the existence of another variable in PHP

Essentially, I'd love to be able to define a variable as one thing unless that thing doesn't exist. I swear that somewhere I saw a shorthand conditional that looked something like this:
$var=$_GET["var"] || "default";
But I can't find any documentation to do this right, and honestly it might have been JS or ASP or something where I saw it.
I understand that all that should be happening in the above code is just to check if either statement returns true. But I thought I saw someone do something that essentially defined a default if the first failed. Is this something anyone knows about and can help me? Am I crazy? It just seems redundant to say:
$var=($_GET["var"]) ? $_GET["var"] : "default";
or especially redundant to say:
if ($_GET["var"]) { $var=$_GET["var"]; } else { $var="default"; }
Thoughts?
Matthew has already mentioned the only way to do it in PHP 5.3. Note that you can also chain them:
$a = false ?: false ?: 'A'; // 'A'
This is not the same as:
$a = false || false || 'A'; // true
The reason why is that PHP is like most traditional languages in this aspect. The logical OR always returns true or false. However, in JavaScript, the final expression is used. (In a series of ORs, it will be the first non-false one.)
var a = false || 'A' || false; // 'A'
var b = true && 'A' && 'B'; // 'B';
In such cases you should be checking for existence of the variable in $_GET and then whether it's valid for your parameters. For example:
$var = (isset($_GET["var"]) && $_GET['var'] !== '') ? $_GET["var"] : "default";
However, this can become pretty unreadable pretty quickly. I'd say keep it readable by first initializing your variable to a safe default, and then overwriting that with an external one, if that's valid:
$var = "default";
if (isset($_GET['var') && $_GET['var'] !== '') {
$var = $_GET['var] ;
}
As for your first example, $var=$_GET["var"] || "default"; exists in Javascript: var someVar = incomingVar || "default";
I've always used empty.
$var = !empty($_GET['var'])?$_GET['var']:'default';

PHP: what's an alternative to empty(), where string "0" is not treated as empty? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Fixing the PHP empty function
In PHP, empty() is a great shortcut because it allows you to check whether a variable is defined AND not empty at the same time.
What would you use when you don't want "0" (as a string) to be considered empty, but you still want false, null, 0 and "" treated as empty?
That is, I'm just wondering if you have your own shortcut for this:
if (isset($myvariable) && $myvariable != "") ;// do something
if (isset($othervar ) && $othervar != "") ;// do something
if (isset($anothervar) && $anothervar != "") ;// do something
// and so on, and so on
I don't think I can define a helper function for this, since the variable could be undefined (and therefore couldn't be passed as parameter).
This should do what you want:
function notempty($var) {
return ($var==="0"||$var);
}
Edit: I guess tables only work in the preview, not in actual answer submissions. So please refer to the PHP type comparison tables for more info.
notempty("") : false
notempty(null) : false
notempty(undefined): false
notempty(array()) : false
notempty(false) : false
notempty(true) : true
notempty(1) : true
notempty(0) : false
notempty(-1) : true
notempty("1") : true
notempty("0") : true
notempty("php") : true
Basically, notempty() is the same as !empty() for all values except for "0", for which it returns true.
Edit: If you are using error_reporting(E_ALL), you will not be able to pass an undefined variable to custom functions by value. And as mercator points out, you should always use E_ALL to conform to best practices. This link (comment #11) he provides discusses why you shouldn't use any form of error suppression for performance and maintainability/debugging reasons.
See orlandu63's answer for how to have arguments passed to a custom function by reference.
function isempty(&$var) {
return empty($var) || $var === '0';
}
The key is the & operator, which passes the variable by reference, creating it if it doesn't exist.
if(isset($var) && ($var === '0' || !empty($var)))
{
}
if ((isset($var) && $var === "0") || !empty($var))
{
}
This way you will enter the if-construct if the variable is set AND is "0", OR the variable is set AND not = null ("0",null,false)
The answer to this is that it isn't possible to shorten what I already have.
Suppressing notices or warnings is not something I want to have to do, so I will always need to check if empty() or isset() before checking the value, and you can't check if something is empty() or isset() within a function.
function Void($var)
{
if (empty($var) === true)
{
if (($var === 0) || ($var === '0'))
{
return false;
}
return true;
}
return false;
}
If ($var != null)

Categories