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 ソースコードリーディング – モデルの取得
尻切れトンボになってしまうが、ひとまずここまで。