web-dev-qa-db-ja.com

PHPでの複数の三項演算子のスタック

これは私が書いたものです:

 $Myprovince = (
($province == 6) ? "city-1" :
($province == 7) ? "city-2" :
($province == 8) ? "city-3" :
($province == 30) ? "city-4" : "out of borders"
);

しかし、すべてのフィールドで値city-4を取得しました。 switch/ifの代わりに三項演算子を使用したいのは、実験してそれがどのように行われるかを確認したいためです。

このコードの何が問題になっていますか?

33
Mac Taylor

他の人はすでにそれを行う正しい方法を提案していますが、本当に三項演算子を使用したい場合は、括弧を次のように使用する必要があります:

$province = 7;
 $Myprovince = (
 ($province == 6) ? "city-1" :
  (($province == 7) ? "city-2" :
   (($province == 8) ? "city-3" :
    (($province == 30) ? "city-4" : "out of borders")))
 );

更新されたリンク

86
codaddict

三項演算子は、左から右に評価されます。したがって、式を適切にグループ化しないと、予期しない結果になります。

PHPのアドバイスは [docs]

3項式の「スタック」を避けることをお勧めします。 1つのステートメント内で複数の三項演算子を使用する場合のPHPの動作は自明ではありません。

あなたのコードは実際には次のように評価されます:

(
    (
        (
            $province == 6 ? "city-1" : $province == 7
        ) ? "city-2" : 
        $province == 8
    ) ? "city-3" : $province == 30
) ? "city-4" : "out of borders";

どこにあるべきか

$province == 6 ? "city-1" : (
    $province == 7 ? "city-2" : (
        $province == 8 ? "city-3" : (
           $province == 30 ? "city-4" : "out of borders"
        )
    )
);

このコードは問題なく見えるかもしれませんが、誰かがそれを読んで、このコードが何をしているかを理解するのに必要な時間よりも多くの時間が必要になります。


あなたはこのようなものでうまくいくでしょう:

$map = array( 6 = >'city-1', 
              7 => 'city-2', 
              8 => 'city-3', 
             30 => 'city-4');

$Myprovince = "out of borders";

if(array_key_exists($province, $map)) {
    $Myprovince = $map[$province];
}

または、コメントで言及されている @ Jonah のように:

$Myprovince = isset($map[$province]) ? $map[$province] : 'out of borders';
33
Felix Kling

そのようなことのために三項演算子を乱用しないでください。これはデバッグをほぼ不可能にします。のようなことをしてみませんか

switch($province) {
    case 6: $Myprovince = "city-1"; break;
    case 7: ...
}

または単にチェーンされたif/then/else

if ($province == 6) {
     $Myprovince = "city-1";
} elseif ($province = ...) {
   ...
}
17
Marc B

一部の人々は、switchステートメントまたはif/elseステートメントの使用を提案しています。しかし、代わりに配列を使用して、保守と読み取りを容易にします。

$provinces = array (
    6 => 'city-1',
    7 => 'city-2',
    8 => 'city-3',
    30 => 'city-4'
);

// then you can call:

$Myprovince = isset($provinces[$province]) ? $provinces[$province] : 'out of borders';

どうして?

コードはおそらく最終的には管理しやすくなります。多分あなたはそれらの州から都市へのマッピングをデータベースからいつか追加したいと思うでしょう。

12
arnorhs

これはPHPに関する質問であることを理解していますが、これは単なる教育的な演習なので、RubyとJavaScriptが実際に期待どおりに動作することを学習することに興味があると思います。

ルビー:

ree-1.8.7-2012.02 :009 > def foo x
ree-1.8.7-2012.02 :010?>   x == 1 ? "city 1" : x == 2 ? "city 2" : "out of borders"
ree-1.8.7-2012.02 :011?>   end
 => nil
ree-1.8.7-2012.02 :012 > foo 1
 => "city 1"
ree-1.8.7-2012.02 :013 > foo 2
 => "city 2"
ree-1.8.7-2012.02 :014 > foo 3
 => "out of borders"

JavaScript:

> function f(x) { return x == 1 ? "city 1" : x == 2 ? "city 2" : "out of borders"; }
undefined
> f(1)
"city 1"
> f(2)
"city 2"
> f(3)
"out of borders"
4
Noah

かっこを追加してみてください:

$Myprovince = (
($province == 6) ? "city-1" :
(($province == 7) ? "city-2" :
(($province == 8) ? "city-3" :
(($province == 30) ? "city-4" : "out of borders"
))));

コードに三項演算子の優先順位に関する問題があります。

しかし、この演算子を本当に削除して、代わりにswitchを使用するようにすべきだと思います。

3
krtek

今日も同じ問題に巻き込まれました。他はすでに許容できる解決策を与えています。 1つのライナーのifsだけに重点を置きます。私の意見ではもっと読みやすいです。

if ($province == 6) $Myprovince = 'city-1';
elseif ($province == 7) $Myprovince = 'city-2';
elseif ($province == 8) $Myprovince = 'city-3';
elseif ($province == 30) $Myprovince = 'city-4';
else $Myprovince = 'out of borders';
0
Fandi Susanto

代わりにスイッチを使用してください。三元演算子は、すぐに理解するのが非常に難しくなるため、実際には単一の条件以上に使用するべきではありません。

switch ($province) {
    case 6:
        $Myprovince = 'city-1';
        break;
    case 7:
        $Myprovince = 'city-2';
        break;
    case 8:
        $Myprovince = 'city-3';
        break;
    case 30:
        $Myprovince = 'city-4';
        break;
    default:
        $Myprovince = 'out of borders';
}
0
Jonah