三項演算子の実行順序

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およびC ++も1を返します





違いは何ですか?



私は長い間この興味深いニュアンスを知っていましたが、昨日、オープンソースの1つでエラーを見つけました。著者は明らかにこのニュアンスを知らず、捕まってしまいました。 したがって、この記事は単なる警告です。 結局のところ、プログラマーが他の言語と同じ動作をphpに期待する場合、彼はがらくたに陥る可能性があります。



この手法は、条件に応じて値を設定するのに非常に便利です。 エレガントなif-else交換。 例:

 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(); }
      
      







間違いを避ける方法は?



最初の方法は、PHPで三項演算子を使用しないことです。

2番目は、括弧を使用して実行順序を直接示すことです。



$ php -r "print true ? 1 : ( true ? 2 : ( true ? 3 : ( true ? 4 : 5 )));"

1







Lispを連想させるものですよね?



なぜこのように起こるのでしょうか?



例としてJavaScriptとPHPを使用して、三項演算子の実行順序を見てみましょう

各言語がどのように機能するかを理解するために、2つのテストスクリプトを作成します。



念のため、 $foo = $lambda('fooMsg', 'fooReturn')



$foo



は、呼び出されたときにコンソールにメッセージ'fooMsg'



表示し、値'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





 <?php $lambda = function ($logMsg, $returnValue) { return function () use ($logMsg, $returnValue) { echo $logMsg . PHP_EOL; return $returnValue; }; }; $cond = array( 'first' => $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








この結果のどちらを結論付けることができます。 Javascriptは、三項演算子を非常に論理的に解析します。 最初に左端の条件をチェックします。 trueの場合、最初のコロンの後の左部分を実行し、trueでない場合は右を返します。

 (cond.first() ? value.first() : (cond.second() ? value.second() : (cond.third() ? value.third() : (value.default())))); /******** * ===> */ true ? 'value.first' : /* ignored */;
      
      







PHPはオリジナルだと考えています。



 ( ( 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'
      
      







公式マニュアルで確認されていること:

 $a = true ? 0 : true ? 1 : 2; // (true ? 0 : true) ? 1 : 2 = 2
      
      







おわりに



一般に、PHPは「最高の側面から」再び姿を現しましたが、問題は重大とはほど遠いものです。 主なことは、それについて知り、PHPの三項演算子に注意することです。



All Articles