whereInの第二引数が空
function getUsersByIds(array $ids) { return User::whereIn('id', $ids)->get(); }
こんな関数を書いたときに、$idsがもし []
だったら?
これでwhereが無いからって全件検索されたら、とんでもない障害に・・・
ですが、Laravelさん、ちゃんとそこはケアしてくれてます。
全件検索じゃないならどうなる?
# php artisan tinker >>> \App\User::whereIn('id', [])->toSql(); => "select * from `users` where 0 = 1"
where 0 = 1
になってますね。
コードを追ってみよう
注意: この先のコードは、Laravel 5.7のコードになります。
whereInで何をする?
クエリビルダのwhereIn関数の一部を紹介すると、
Illuminate/Database/Query/Builder.php
$this->wheres[] = compact('type', 'column', 'values', 'boolean'); foreach ($values as $value) { if (! $value instanceof Expression) { $this->addBinding($value, 'where'); } }
この $this->wheres
に値を入れるのと、 $this->bindings
に値を入れる作業がされます。
今回バインドされる値が無いので、 $this->where
に着目すると、
array:1 [ 0 => array:4 [ "type" => "In" "column" => "id" "values" => [] "boolean" => "and" ] ]
このような値が入ります。
だからどうしたというのは、実際にget関数などで、クエリ生成をするときに明らかになります。
getとかで何をする?
get関数などでクエリを生成するときですが、結論から言うと、
全件検索されるのは、 $this->whereが空のときなので、 $this->whereの中身があるから、全件検索されない
実際のコードは以下にあります。
Illuminate/Database/Query/Grammars/Grammar.php
protected function compileWheres(Builder $query) { if (is_null($query->wheres)) { return ''; } if (count($sql = $this->compileWheresToArray($query)) > 0) { return $this->concatenateWhereClauses($query, $sql); } return ''; }
if文で、 is_null($query->wheres)
が書かれていますね。空じゃなければ、where句の生成がされます。
where 0 = 1はどこから?
では、 where 0 = 1
はどっから来たんだと。
その秘密は、whereIn関数の解決にあります。
Illuminate/Database/Query/Grammars/Grammar.php
protected function whereIn(Builder $query, $where) { if (! empty($where['values'])) { return $this->wrap($where['column']).' in ('.$this->parameterize($where['values']).')'; } return '0 = 1'; }
さて、少し前の変数を思い出しましょう。
array:1 [ 0 => array:4 [ "type" => "In" "column" => "id" "values" => [] "boolean" => "and" ] ]
if文の中身は、 (! empty($where['values']))
なので、一番下にある、 return '0 = 1'
にたどり着くわけですね。
上手く出来てますね(^q^)
最後に
今回の例を見て、『へー』で終わらせるのもいいですが、
今後クエリビルダを使うときには、
Illuminate/Database/Query/Grammars/Grammar.php Illuminate/Database/Query/Builder.php
この2ファイルを読むと、詰まったときに幸せになれるかもしれません。
あと、Laravelのコードは結構きれいに書かれているので、今後コードを書くときの参考になるかもしれませんよ!
コードリーディング、おすすめです!