Modelにcreate()メソッドがない
LaravelのUserや作成したモデルで呼び出すcreate()メソッドについて調べた過程。
たとえばLaravelでモデルとコントローラーをPost、PostControllerのように生成し、store()アクション内でマスアサインメントによってデータを登録する場合に、以下のように書き、モデルクラスのスタティックメソッドcreate()を呼び出している。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | class PostController extends Controller {     ........     public function store(Request $request)     {         Post::create([           'comment' => $request->comment,         ]);         return redirect()->route('posts.index');     }     ........ } | 
ここでPostモデルのクラスを見てみると、EloquentのModelクラスを継承している。
| 1 2 3 4 5 6 7 8 9 | <?php namespace App; use Illuminate\Database\Eloquent\Model; class Post extends Model { } | 
ところがIlluminate\Database\Eloquent\Modelクラスなどをたどってみても、create()メソッドが見当たらなかった。
マジックメソッドで実装している
以下のように、Modelクラスではマジックメソッド__call()、__callstatic()が定義されている。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |     public function __call($method, $parameters)     {         if (in_array($method, ['increment', 'decrement'])) {             return $this->$method(...$parameters);         }         if ($resolver = (static::$relationResolvers[get_class($this)][$method] ?? null)) {             return $resolver($this);         }         return $this->forwardCallTo($this->newQuery(), $method, $parameters);     }     public static function __callStatic($method, $parameters)     {         return (new static)->$method(...$parameters);     } | 
まず、Post::create()が実行されると、
- Postクラスには- static create()がない
- 継承元のModelクラスにもstatic create()がない
- Model::__callstatic()が呼ばれる
- new staticがlate static bindingで実行されて- new Post()と解釈される
- Postインスタンスには- create()がない
- 継承元のModelにもcreate()がない
- Model::__call()が呼ばれる
この__call()メソッドの動作はよくわかっていないが、create()の場合は最終的に以下が実行されるようだ。
| 1 | return $this->forwardCallTo($this->newQuery(), $method, $parameters); | 
forwardCallTo()はModelでuseしているForwardsCallsトレイトのメソッドを呼んでいるが、要するにnewQuery()の戻り値のオブジェクトで定義されている$method(この場合はcreate())を呼んでいる。
| 1 2 3 4 5 6 7 8 9 10 11 12 | trait ForwardsCalls {     protected function forwardCallTo($object, $method, $parameters)     {         try {             return $object->{$method}(...$parameters);         } catch (Error|BadMethodCallException $e) {             ........         }     }     ........ } | 
ここからどんどん複雑になっていくので手に負えなくなるが、参考サイトを拝見するとEloquent\Builderというクラスのインスタンスが戻り値になるようで、その中にcreate()が定義されていた。
参考サイト:【Laravel】 第1回 Eloquent ソースコードリーディング – モデルの取得
尻切れトンボになってしまうが、ひとまずここまで。