The ternary operator execution order
There is an interesting feature of ternary operator in php - a specific and unique order of execution.
I know about this interesting nuance for a long time, but just yesterday I discovered an error in one of the open source sources: the author clearly did not know about this nuance and got caught. Therefore, this article is just a warning. After all, if a programmer expects the same behavior from php as from other languages, he could fall into a crap.
This technique is very convenient for setting values, depending on the conditions. Elegant if-else replacement. For instance:
The first way is not to use the ternary operator in php.
The second is to directly indicate the order of execution using parentheses:
Something reminiscent of Lisp, right?
Let's look at the execution order of the ternary operator using JavaScript vs PHP as an example.
We will write two test scripts to understand how each language works.
Just in case, I’ll explain that when
Which of this result can be concluded. Javascript parses the ternary operator quite logically. First checks the leftmost condition. If it is true, then it executes and returns the left part after the first colon, if not true, then the right.
PHP thinks original.
What is confirmed in the official manual :
In general, PHP showed itself again “from the best side”, but the problem is far from critical. The main thing is to know about it and be careful with the ternary operator in PHP.
$ python -c "print 1 if true else 2 if true else 3 if true else 4 if true else 5"
1
$ node -e " true ? 1 : true ? 2 : true ? 3 : true ? 4 : 5"
1
$ perl -e "print true ? 1 : true ? 2 : true ? 3 : true ? 4 : 5"
1
$ ruby -e "print true ? 1 : true ? 2 : true ? 3 : true ? 4 : 5"
1
$ php -r "print true ? 1 : true ? 2 : true ? 3 : true ? 4 : 5;"
4
Java and C ++ will also return 1What's the difference?
I know about this interesting nuance for a long time, but just yesterday I discovered an error in one of the open source sources: the author clearly did not know about this nuance and got caught. Therefore, this article is just a warning. After all, if a programmer expects the same behavior from php as from other languages, he could fall into a crap.
This technique is very convenient for setting values, depending on the conditions. Elegant if-else replacement. For instance:
value = isCondFirst() ? valueFirst() :
isCondSecond() ? valueSecond() :
isCondThird() ? valueThird() :
valueDefault();
/********** Вместо **********/
if (isCondFirst()) {
value = valueFirst();
} else if (isCondSecond()) {
value = valueSecond();
} else if (isCondThird()) {
value = valueThird();
} else {
value = valueDefault();
}
How to avoid a mistake?
The first way is not to use the ternary operator in php.
The second is to directly indicate the order of execution using parentheses:
$ php -r "print true ? 1 : (true ? 2 : (true ? 3 : (true ? 4 : 5)));"
1
Something reminiscent of Lisp, right?
Why does it even happen this way?
Let's look at the execution order of the ternary operator using JavaScript vs PHP as an example.
We will write two test scripts to understand how each language works.
Just in case, I’ll explain that when
$foo = $lambda('fooMsg', 'fooReturn')
, $foo
contains a function that, when called, displays a message in the console 'fooMsg'
and returns a value'fooReturn'
$ cat ternary.js
var lambda = function (logMsg, returnValue) { return function () { console.log(logMsg); return returnValue; }; }; var cond = { first : lambda('cond.first' , true), second: lambda('cond.second', true), third : lambda('cond.third' , true) }; var value = { first : lambda('value.first' , 'first'), second : lambda('value.second' , 'second'), third : lambda('value.third' , 'third'), default: lambda('value.default', 'default') }; console.log( 'result: ', cond.first() ? value.first() : cond.second() ? value.second() : cond.third() ? value.third() : value.default() );
$ node ternary.js
cond.first
value.first
result: first$ cat ternary.php
$lambda('cond.first' , true), 'second'=> $lambda('cond.second', true), 'third' => $lambda('cond.third' , true), ); $value = array( 'first' => $lambda('value.first' , 'first'), 'second' => $lambda('value.second' , 'second'), 'third' => $lambda('value.third' , 'third'), 'default'=> $lambda('value.default', 'default'), ); echo 'result: ' . ( $cond['first']() ? $value['first']() : $cond['second']() ? $value['second']() : $cond['third']() ? $value['third']() : $value['default']() ) . PHP_EOL; ?>
$ php ternary.php
cond.first
value.first
value.second
value.third
result: third
Which of this result can be concluded. Javascript parses the ternary operator quite logically. First checks the leftmost condition. If it is true, then it executes and returns the left part after the first colon, if not true, then the right.
(cond.first() ? value.first() :
(cond.second() ? value.second() :
(cond.third() ? value.third() :
(value.default()))));
/********
* ===>
*/
true ? 'value.first' : /* ignored */;
PHP thinks original.
(
(
cond.first() ?
value.first() :
cond.second()
) ?
value.second() :
cond.third()
) ?
value.third() :
value.default();
/********
* ===>
*/
(
(
'value.first'
) ?
value.second() :
cond.third()
) ?
value.third() :
value.default();
/********
* ===>
*/
(
'value.second'
) ?
value.third() :
value.default();
/********
* ===>
*/
'value.third'
What is confirmed in the official manual :
$a = true ? 0 : true ? 1 : 2; // (true ? 0 : true) ? 1 : 2 = 2
Conclusion
In general, PHP showed itself again “from the best side”, but the problem is far from critical. The main thing is to know about it and be careful with the ternary operator in PHP.