if文の中で&&や||を使うことがあるのですが、意図した挙動にならない場合があります。原因は何でしょうか?
すべての計算をしてから結果を返すのでなく、左側から計算を行い、条件を満たした時点で結果を返していることが原因かもしれません。
- &&:左側の演算結果がtrueであれば右側の処理を実行する
- ||:左側の演算結果がfalseであれば右側の処理を実行する
詳しく見ていきましょう!
論理演算子とは
論理演算子とは「true、falseを計算して全体としてtureかfalseかを返す仕組み」です。
- &&(かつ):左側と右側の結果の両方がtrueの場合のみtrueを返す
- ||(または):左側と右側の値のどちらか一方がtureの場合trueを返す
- !(否定):trueならfalse、falseならtrueを返す
&&(かつ)
左側と右側の結果の両方がtrueの場合のみtrueを返します。
左側 | 右側 | 結果 |
TRUE | TRUE | TRUE |
TRUE | FALSE | FALSE |
FALSE | TRUE | FALSE |
FALSE | FALSE | FALSE |
プログラミング的な意味合い
&&の場合は、左側の演算結果がtrueであれば右側の処理を実行します。
つまり、左辺と右辺の両方を実行した結果で判定しているわけではありません。「かつ」なので、左辺がfalseの段階で条件を満たさなくなり処理を終了します。
ユーザーidが存在している場合、ユーザーが退職しているかチェックする処理を考えます。
行いたいことのイメージは次のとおり。
if (isset($user_id)) { $userExist = User::where('id', $user_id)->where('is_retired', false)->exists(); } else { $userExist = false; }
ユーザーidが存在している場合は退職しているかのチェックを行い、ユーザーidがない場合はfalseを返しています。$user_idがない場合は、そもそもクエリが走らないようにしています。
少し冗長なので書き換えます。三項演算子で一行になりました。
三項演算子は?の前の部分がtureなら?の後の処理を、falseなら:の後の処理を行うことができる仕組みでしたね。
$userExist = isset($user_id) ? User::where('id', $user_id)->where('is_retired', false)->exists() : false;
しかし、true、falseを返すのであればまだ冗長なので書き換えてみます。
$userExist = isset($user_id) && User::where('id', $user_id)->where('is_retired', false)->exists();
左辺のisset($user_id) がfalseの場合、処理が終了するので右辺のクエリが実行されることはありません。
これが右辺と左辺を逆に書いていると、クエリの実行が先に行われるので、$user_idがない場合、不要なクエリが毎回走ってしまいます。
$userExist = User::where('id', $user_id)->where('is_retired', false)->exists() && isset($user_id) ;
||(または)
左側と右側の値のどちらか一方がtureの場合trueを返します。
左側 | 右側 | 結果 |
TRUE | TRUE | TRUE |
TRUE | FALSE | TRUE |
FALSE | TRUE | TRUE |
FALSE | FALSE | FALSE |
プログラミング的な意味合い
||の場合は、左側の演算結果がfalseであれば右側の処理を実行します。
つまり、左辺と右辺の両方を実行した結果で判定しているわけではありません。「または」なので、左辺がtrueの段階で条件を満たし処理を終了します。
ユーザーidが存在している場合、ユーザーが退職していないかチェックする処理を考えます。今回は退職していない場合がtrueとなります。
行いたいことのイメージは次のとおり。
if (is_null($user_id)) { $userNotExist = true; } else { $userNotExist = User::where('id', $user_id)->where('is_retired', false)->doesntExist(); }
ユーザーidが存在している場合は退職しているかのチェックを行い、ユーザーidがない場合はtrueを返しています。$user_idがない場合は、そもそもクエリが走らないようにしています。
少し冗長なので書き換えます。三項演算子で一行になりました。
$userExist = is_null($user_id) ? true : User::where('id', $user_id)->where('is_retired', false)->doesntExist();
さらに簡略化します。
$userExist = is_null($user_id) || User::where('id', $user_id)->where('is_retired', false)->doesntExist();
左辺のis_null($user_id)がtrueの場合、処理が終了するので右辺のクエリが実行されることはありません。
これが右辺と左辺を逆に書いていると、クエリの実行が先に行われるので、$user_idがない場合、不要なクエリが毎回走ってしまいます。
$userExist = User::where('id', $user_id)->where('is_retired', false)->doesntExist() || is_null($user_id);
まとめ
論理演算子とは「true、falseを計算して全体としてtureかfalseかを返す仕組み」です。
よく利用されるのは次の3つ。
- &&(かつ):左側と右側の結果の両方がtrueの場合のみtrueを返す
- ||(または):左側と右側の値のどちらか一方がtureの場合trueを返す
- !(否定):trueならfalse、falseならtrueを返す
かつ(&&)、または(||)のプログラミング的な意味合いは次のとおり。
- &&:左側の演算結果がtrueであれば右側の処理を実行する
- ||:左側の演算結果がfalseであれば右側の処理を実行する
左側の値から順番に処理が行われるため、記述順を間違えると意図しない挙動になる場合があります。論理演算子を利用する場合は、実行順を考慮して作成していきましょう。
コメント