PHPの三項演算子がネストするとおかしくなる話と対策
PHPの三項演算子がネストするとおかしくなる
検証コード
<?php function fizzbuzz($num) { return ($num % 15 == 0) ? 'FizzBuzz' : ($num % 5 == 0) ? 'Fizz' : ($num % 3 == 0) ? 'Buzz' : $num ; } for ($i = 1; $i < 20; $i++) { echo fizzbuzz($i) . "\n"; } ?>
結果
1 2 Buzz 4 Buzz Buzz 7 8 Buzz Buzz 11 Buzz 13 14 Buzz 16 17 Buzz 19
http://d.hatena.ne.jp/omoon/20071127/1196174396
とか
http://d.hatena.ne.jp/pasela/20080524/ternary
とかで指摘されている話。
論理演算子で逃げようとしたけどダメ
PHPの論理演算子はboolしか返さないので、これもPerlと同じのりで使おうとするとはまれる。
検証コード
<?php function fizzbuzz($i, $num, $str) { return ($i % $num == 0 ) ? $str : false; } for ($i = 1; $i < 20; $i++) { $val = fizzbuzz($i, 15, 'FizzBuzz') || fizzbuzz($i, 5, 'Fizz') || fizzbuzz($i, 3, 'Buzz') || $i; echo $val . "\n"; } ?>
結果
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
対策
http://phpspot.org/blog/archives/2007/12/phpifelse3.html
に書いてある感じで1行にまとめると、括弧の対応がパッと見でわかんなくなるのでキモい。
なので、行頭を揃えるのを諦めて、評価順通りに括弧をつけて改行とインデントするのがベターかな。
検証コード
<?php for ($i = 1; $i < 20; $i++) { $val = ($i % 15 == 0) ? 'FizzBuzz' : ( ($i % 5 == 0) ? 'Fizz' : ( ($i % 3 == 0) ? 'Buzz' : $i ) ); echo( $val . "\n" ); } ?>
結果
1 2 Buzz 4 Fizz Buzz 7 8 Buzz Fizz 11 Buzz 13 14 FizzBuzz 16 17 Buzz 19
対策その2
もう少し調べてみたら、?:演算子がPerlのor演算子的に動いてくれるらしい。
検証コード
<?php function fizzbuzz($val, $num, $str) { return ($val % $num == 0) ? $str : false; } foreach (range(1, 19) as $i) { $val = fizzbuzz($i, 15, 'FizzBuzz') ?: fizzbuzz($i, 5, 'Fizz') ?: fizzbuzz($i, 3, 'Buzz') ?: $i; echo $val . PHP_EOL; } ?>
結果
1 2 Buzz 4 Fizz Buzz 7 8 Buzz Fizz 11 Buzz 13 14 FizzBuzz 16 17 Buzz 19