0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Laravel】Modelクラスに存在しないfindメソッドが実行できる仕組み(マジックメソッドとBuilderへの動的委譲)

0
Posted at

【Laravel】Modelクラスに存在しないfindメソッドが実行できる仕組み(マジックメソッドとBuilderへの動的委譲)

1. 概要 / 結論

  • LaravelのEloquentにおいて、Model クラス(およびその継承クラス)で find() メソッドが呼び出せる内部メカニズムに関する備忘録。
  • find() は Model.php に直接定義されておらず、PHPのマジックメソッド(__callStatic / __call)経由で Builder.php(Illuminate\Database\Eloquent\Builder)へ動的に処理が委譲される。

2. 課題・背景(なぜ調べたか)

  • Eloquentのソースコード(Model.php)を確認した際、頻繁に利用する find() メソッドの定義が存在せず、なぜ User->find(1) などの記述で正常に動作するのか疑問に思ったため。
  • 親子関係(クラス継承)ではない Model と Builder がどのように連携してクエリを発行しているのか、構造を把握したかったため。

3. 実装・解決方法 / 使い方

find() 呼び出し時の動的委譲フロー

User::find(1) や $user->find(1) を実行すると、以下のステップで Builder.php の find() メソッドへと到達する。

// 1. 静的呼び出し(User::find(1))の場合
// Model.php に静的 find() が存在しないため __callStatic が発動
public static function __callStatic($method,$parameters)
{
    // 遅延静的結合 (new static) により、呼び出し元(Userクラス)のインスタンスを生成して __call へ接続
    return (new static)->$method(...$parameters);
}

// 2. インスタンス呼び出し((new User)->find(1))に変換された場合
// Model.php にインスタンスメソッドの find() も存在しないため __call が発動
public function __call($method,$parameters)
{
    // newQuery() で Eloquent Builder インスタンスを生成し、処理を Builder::find() へ横流しする
    return $this->forwardCallTo($this->newQuery(), $method,$parameters);
}

// 3. 委譲先:Illuminate/Database/Eloquent/Builder.php
public function find($id,$columns = ['*'])
{
    // 単一IDか配列かに応じてクエリを組み立てて実行
    if (is_array($id) \vert{}\vert{}$id instanceof Arrayable) {
        return $this->findMany($id,$columns);
    }

    return $this->where($this->model->getKeyName(), $id)->first($columns);
}

なぜこのような設計なのか

Model と Builder で役割を明確に分担させる設計思想(関心の分離)に基づいている。

  • Model.php(データの表現): 属性(カラム)の保持、リレーション定義、イベントハンドリングなどを担当。
  • Builder.php(クエリの構築・実行): where、orderBy、limit、find などのSQL生成と実行を担当。

マジックメソッドを用いて Model から Builder へ委譲することで、Model.php の巨大化(Fat Model)を防ぎつつ、直感的でシンプルな記述法を実現している。

4. はまりポイント・注意点

  • new static()(遅延静的結合)の動き:
    __callStatic 内で記述されている (new static()) は、PHP標準の遅延静的結合(Late Static Bindings)を利用している。親クラスの Model ではなく、呼び出された子クラス(例: User や Post)のインスタンスを動的に生成する。

  • ローカルスコープ(scopeXxx)との混同:
    User::active() などのローカルスコープも __callStatic / __call 経由で呼び出されるが、find() の委譲ロジックはスコープ機能ではなく、PHPの標準機能(static 構文)とマジックメソッドによる動的委譲そのものである。

5. 参考リンク

  • Laravel Official Documentation - Eloquent ORM
  • GitHub - laravel/framework (Illuminate/Database/Eloquent/Model.php)
  • GitHub - laravel/framework (Illuminate/Database/Eloquent/Builder.php)
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?