How does this nested ternary expression work? [duplicate] - php

This question already has answers here:
Stacking Multiple Ternary Operators in PHP
(11 answers)
Closed 2 years ago.
I was making a clamp() function in php, and decided to go for a nested ternary expression just to try it.
In the end, I settled with this (working) function :
function clamp($value, $min, $max){
return
$value<$min ? $min
: ($value>$max ? $max
: $value);
}
However, why are the brackets around the second expression required? I had tried removing them afterward :..
function clamp($value, $min, $max){
return
$value<$min ? $min
: $value>$max ? $max
: $value;
}
... but in this version, it will return $max if $value is smaller than $min. I just don't understand how it comes to that result.

I had hear of php having "left associativity" with ternary, though I never understood what it meant:
Take
$bool ? "a" : $bool ? "b" : "c"
Right associativity is: $bool ? "a" : ($bool ? "b" : "c")
Left associativity is : ($bool ? "a" : $bool) ? "b" : "c"
So in the end php will always it evaluate to either b or c.
Bonus:
$bool ? $bool ? "c" : "b" : "a"
Here is a syntax that I think wouldn't change meaning based on associativity.
I wonder whether people managed to find a pretty indentation for this variant.

Related

Nested shorthand if bug [duplicate]

Why is this printing 2?
echo true ? 1 : true ? 2 : 3;
With my understanding, it should print 1.
Why is it not working as expected?
Because what you've written is the same as:
echo (true ? 1 : true) ? 2 : 3;
and as you know 1 is evaluated to true.
What you expect is:
echo (true) ? 1 : (true ? 2 : 3);
So always use braces to avoid such confusions.
As was already written, ternary expressions are left associative in PHP. This means that at first will be executed the first one from the left, then the second and so on.
Separate second ternary clause with parentheses.
echo true ? 1 : (true ? 2 : 3);
Use parentheses when in doubt.
The ternary operator in PHP is left-associative in contrast to other languages and does not work as expected.
from the docs
Example #3 Non-obvious Ternary Behaviour
<?php
// on first glance, the following appears to output 'true'
echo (true?'true':false?'t':'f');
// however, the actual output of the above is 't'
// this is because ternary expressions are evaluated from left to right
// the following is a more obvious version of the same code as above
echo ((true ? 'true' : false) ? 't' : 'f');
// here, you can see that the first expression is evaluated to 'true', which
// in turn evaluates to (bool)true, thus returning the true branch of the
// second ternary expression.
?>
In your case, you should consider the priority of executing statements.
Use following code:
echo true ? 1 : (true ? 2 : 3);
For example,
$a = 2;
$b = 1;
$c = 0;
$result1 = $a ** $b * $c;
// is not equal
$result2 = $a ** ($b * $c);
Are you have used parentheses in expressions in mathematics? - Then, that the result, depending on the execution priority, is not the same. In your case, ternary operators are written without priorities. Let the interpreter understand in what order to perform operations using parentheses.
Late, but a nice example for being carefull from now:
$x = 99;
print ($x === 1) ? 1
: ($x === 2) ? 2
: ($x === 3) ? 3
: ($x === 4) ? 4
: ($x === 5) ? 5
: ($x === 99) ? 'found'
: ($x === 6) ? 6
: 'not found';
// prints out: 6
Result of PHP 7.3.1 (Windows Commandline). I can not understand, why they changed it, because the code becomes really unreadable, if I try to change this.

PHP - correct ternary implementation [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
Improve this question
Ok,
so consider the following:
$this->foo = isset($_GET['foo']) && !empty($_GET['foo']) ? $_GET['foo'] : NULL;
and this:
$this->foo = (isset($_GET['foo']) && !empty($_GET['foo'])) ? $_GET['foo'] : NULL;
When I write an if / else statement with multiple checks, I generally include the extra parenthesis as in the second example. In the ternary, both examples work.
Should I add the extra parenthesis as on the bottom? Or go with the first?
Thanks
Operator precedence is the issue as to when parenthesis are necessary (notwithstanding readability).
When dealing with the ternary operator look at the order PHP uses to group expressions, start with the ternary operator(s) and examine the operators that are grouped after the ternary operator. Those are the operators that have the potential to produce erroneous output.
PHP Operator Precedence, starting with ternary:
Assoc. Operators Additional Information
...
left ? : ternary
right = += -= *= **= /= .= %=
&= %= &= |= ^= <<= >>= => assignment
left and logical
left xor logical
left or logical
left , many uses
In this case there are the assignment operators, the lower precedence logical operators, and comma.
It appears the ternary and assignment are equal, therefore grouping is determined by their associativity when the two are in the same statement.
$a = true? 'yes': 'no';
// $a is assigned 'yes'
Assignment is right associative so, in relation to the =, expressions are grouped right to left. In this case the ternary comes first (rightmost) and the statement works as expected.
That leaves the lower precedence boolean and the comma.
echo true and true? 'yes': 'no';
// Echos: 1
// Grouped like: echo true and (true? 'yes': 'no');
Not as expected. Use parenthesis to force intended grouping:
echo (true and true)? 'yes': 'no';
// Echos: yes
When using higher precedence boolean operators, which are grouped before the ternary operator, parenthesis are not necessary.
echo true && true? 'yes': 'no';
// Echos: yes
Bottom line, when operator precedence is unclear, or readability is desired, use parenthesis.
The PSR-2 standard specifically omits any opinion on operators. But in this case, i'll go with the simple one:
$this->foo = isset($_GET['foo']) && !empty($_GET['foo']) ? $_GET['foo'] : NULL;
I am for the first approach:
$this->foo = isset($_GET['foo']) && !empty($_GET['foo']) ? $_GET['foo'] : NULL;
simplified to
$this->foo = !empty($_GET['foo']) ? $_GET['foo'] : NULL;
empty already check the isset. I would include parathenis in this case only when condition has more then 3 statements. Consider that the 1 line if/else normally is used when the condition is simple, other wise to have a more readable if else you should go with classic if {} else {}

Return statement shorthand syntax [duplicate]

This question already has answers here:
What does the question mark and the colon (?: ternary operator) mean in objective-c?
(13 answers)
Closed 8 years ago.
I am new to php developing but so far have been able to do whatever I want. I recently came across a strange syntax of writing a return statement:
public static function return_taxonomy_field_value( $value )
{
return (! empty(self::$settings['tax_value']) ) ? self::$settings['tax_value'] : $value;
}
I get the return() and the !empty() but after that it has a ? and that's where I get lost. Any help is much appreciated! Thanks guys
This is a ternary operator, a short version of the if statement.
This:
$a = $test ? $b : $c;
is the same as:
if($test)
{
$a=$b;
}
else
{
$a=$c;
}
so basically your example is equivalent to:
if(! empty(self::$settings['tax_value'])
{
return self::$settings['tax_value'];
}
else
{
return $value;
}
You can find some more info here, together with some tips for precautions when using ternary operators.
Important note about the difference from other languages
Since the question is marked as a duplicate of another question that deals with ternary operator in Objective-C, I feel this difference needs to be addressed.
The ternary operator in PHP has a different associativity than the one in C language (and all others as far as I know). To illustrate this, consider the following example:
$val = "B";
$choice = ( ($val == "A") ? 1 : ($val == "B") ? 2 : ($val == "C") ? 3 : 0 );
echo $choice;
The result of this code (in PHP) will be 3, even though it would seem that 2 should be the correct answer. This is due to weird associativity implementation that threats the upper expression as:
( ( ( ($val=="A") ? 1 : ($val=="B") ) ? 2 : ) ($val=="C") ? 3 : 0 )
▲ ▲ ▲ ▲
| | | |
\ \_____________________________/ /
\_______________________________________/
This is called the ternary operator - have a look here
This basically translates to [statement] ? [true execution path] : [false execution path]
In your case, this would do the following:
if(! empty(self::$settings['tax_value']) )
return self::$settings['tax_value'];
else
return $value;
It is a shorthand if statement. Consider the following code
$Test = true ? 1 : 3;
// test is 1
$Test = false ? 1 : 3;
// test is 3

PHP Programming Syntax Question 'x ? x : x;' [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
What is the PHP ? : operator called and what does it do?
I've been programming PHP for years, but have never understood what this syntax does or means. I'm hoping you guys can explain it to me, it's about time I knew the answer:
list($name, $operator) = (strpos($key, '__')) ? explode('__', $key) : array($key, null);
Specifically, I'm curious about the SOMETHING ? SOMETHING : SOMETHING;
It's shorthand for if() { } else {}.
if($i == 0) {
echo 'hello';
} else {
echo 'byebye';
}
is the same as:
echo $i == 0 ? 'hello' : 'byebye';
The first statement after '?' is executed if the first expression before '?' is true, if not the last is executed. It also evaluates to the value of the executed expression.
Its conditional operator just like if in simple words if in one line
(condition) ? statement1 : statement2
If condition is true then execute statement1 else statement2
this is the pure if else tertiary operation
if(a==b) {
c = 3;
} else {
c = 4;
}
this is same as
c = (a==b) ? 3:4;

PHP nested conditional operator bug?

return
true ? 'a' :
false ? 'b' :
'c';
This should return 'a', but it doesn't. It returns 'b' instead. Is there a bug in PHP's order of handling the different parts of the conditional operators?
I got the idea from Are multiple conditional operators in this situation a good idea? where it does seem to work correctly.
(the true and false are for the purpose of the example, of course. in the real code they are statements that evaluate to true and false respectively. yes, i know that for sure)
It is recommended that you avoid
"stacking" ternary expressions. PHP's
behaviour when using more than one
ternary operator within a single
statement is non-obvious
From the PHP Manual under "Non-obvious Ternary Behaviour".
Ternary operators are evaluated left to right, so unless you add it the braces it doesn't behave as you expect. The following would work though,
return (true ? "a" : (false ? "b" : "c"));
Suspect it's evaluating (true ? 'a' : false) as the input to the second ternary operator and interpreting 'a' as true. Try bracketing appropriately.
order of operations:
>>> return true ? 'a' : false ? 'b': 'c';
'b'
>>> return true ? 'a' : (false ? 'b': 'c');
'a'
Let me explain in same way it was explained to me. But you have to pay attention in parenthesis to understand what is happening.
The PHP
The PHP code below
true ? "a" : false ? "b" : "c"
Is equivalent to:
(true ? "a" : false) ? "b" : "c"
Another languages
The code below
true ? "a" : false ? "b" : "c"
Is equivalent to:
true ? "a" : (false ? "b" : "c")

Categories