LoginSignup
23
28

More than 3 years have passed since last update.

routes/web.php が読み込まれて実行されるまでを理解する

Last updated at Posted at 2020-04-29

まえがき

背景

エンジニア仲間でLaravelのソースコードを輪読することにしました。Laravelのソースコードとは言っても膨大な量があるので、まずはルーティング処理から読んでいきます。

1回目の先週はKernelやFacadeなどの概念をさらいながら App\Providers\RouteServiceProvider クラスの mapWebRoutes() メソッドを読むという発表がありました。2回目の今日はルーティング情報の設定がどのように行われるのかを厳密に読んでいきたいと思います。

ローカル開発環境

macOSです。

> sw_vers -productVersion 
10.15.4
> php --version
PHP 7.2.30 (cli) (built: Apr 23 2020 02:40:39) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.2.30, Copyright (c) 1999-2018, by Zend Technologies
> composer --version
Composer version 1.10.5 2020-04-10 11:44:22

ソースコードを読むアプリケーションの作成方法

今回読むソースコードは Installation - Laravel - The PHP Framework For Web Artisans > Installing LaravelVia Laravel Installer に書いてある手順に従ってローカルで作成したものです。

routes/web.php を見てみよう

routes/web.php
<?php

use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
    return view('welcome');
});

routes/web.php は何ですか?

長部はこのように理解しています ↓

  • 私たち アプリケーションの開発者が編集するファイル である。すなわち、フレームワークのファイルではなく、アプリケーションによって異なるファイルである。
  • ブラウザからアプリケーションにアクセスされた時の ルーティング情報を記述するファイル である。ここで、 ルーティング情報 という用語を「これこれのHTTPメソッドでこれこれのURIをリクエストされたとき、これこれのControllerのこれこれのActionを実行する」もしくは「これこれのHTTPメソッドでこれこれのURIをリクエストされたとき、これこれのViewをレンダリングしてレスポンスを返す」といった情報の意味で使っている。また、 ブラウザ と言ったが、これは Webクライアント の方が正確である。
  • HTTPリクエストのうち、 ユーザーが見るページのルーティング情報を記述するファイル であって、APIなどユーザーがレスポンスを直接は見ないリクエストを記述するファイルではない。

参考文献 ↓

次は何をしますか?

  • Route::get('/', function () { ... }); を実行した時に起きることを1段階深掘りします。
  • 深掘りする過程で、必要なら routes/web.php が読み込まれるまでに起きることを理解します。

Illuminate\Support\Facades\Route の定義を見てみよう

vendor/laravel/framework/src/Illuminate/Support/Facades/Route.phpから抜粋
<?php

namespace Illuminate\Support\Facades;

/**
 * @method static \Illuminate\Routing\Route fallback(array|string|callable|null $action = null)
 * (中略)
 * @method static \Illuminate\Routing\Route getCurrentRoute()
 *
 * @see \Illuminate\Routing\Router
 */
class Route extends Facade
{
    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor()
    {
        return 'router';
    }
}

Illuminate\Support\Facades\Route クラスIlluminate\Support\Facades\Facade クラスを継承していることがわかったので、 Illuminate\Support\Facades\Facade の定義も見てみましょう。

vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.phpから抜粋
<?php

namespace Illuminate\Support\Facades;

use Closure;
use Mockery;
use Mockery\MockInterface;
use RuntimeException;

abstract class Facade
{
    /**
     * The application instance being facaded.
     *
     * @var \Illuminate\Contracts\Foundation\Application
     */
    protected static $app;

    // 中略

    /**
     * Handle dynamic, static calls to the object.
     *
     * @param  string  $method
     * @param  array  $args
     * @return mixed
     *
     * @throws \RuntimeException
     */
    public static function __callStatic($method, $args)
    {
        $instance = static::getFacadeRoot();

        if (! $instance) {
            throw new RuntimeException('A facade root has not been set.');
        }

        return $instance->$method(...$args);
    }
}

この2つのファイルを見ると、 Route::get('/', function () { ... }); を1段階深掘りするためには Illuminate\Support\Facades\Route クラスか Illuminate\Support\Facades\Facade クラスの定義を読めばいい ことがわかります。その理由は以下のようなものです ↓

  • Illuminate\Support\Facades\Route クラスは Illuminate\Support\Facades\Facade クラスを継承している。
  • Illuminate\Support\Facades\Facade クラスはどっかのクラスを継承していない。
  • 2つのクラスともどっかのインターフェースを実装していない。 => メソッドの実装を探すときにはインターフェースを見る必要がないことに気づいたのですが、PHPマニュアルへのリンクを残したいので打ち消し線を引いておきました。
  • 2つのクラスともどっかのトレイトを追加していない。

Route::get() メソッドの実装はどこにありますか?

結論はこうです ↓

  • 1段階深掘りするなら Route::get() の実装は Illuminate\Support\Facades\Facade クラスの __callStatic() メソッド である。
  • それ以上深掘りするとなんだかよくわからなくなる。

Illuminate\Support\Facades\Facade::__callStatic() メソッドを読めばいいという結論に至る過程は以下のようなものです ↓

  1. Illuminate\Support\Facades\Route クラスには get() メソッドが定義されていない。
  2. Illuminate\Support\Facades\Route クラスの親クラスである Illuminate\Support\Facades\Facade クラスにも get() メソッドが定義されていない。
  3. 2つのクラスともどっかのトレイトを追加しているわけではないため、 get() メソッドの実装がどっか別のトレイトで定義されているわけでもない。
  4. 明示的な実装が定義されていないならマジックメソッド __callStatic() が定義されていないとおかしい。

Route::get() を実行した時に何が起きますか?

↓ これを実行することは、

Route::get('/', function () {
    return view('welcome');
});

↓ これを実行することと同じと考えてよいです。

Illuminate\Support\Facades\Route::__callStatic('get', [
    '/',
    function () {
        return view('welcome');
    },
]);

PHP: オーバーロード - Manual > メソッドのオーバーロード によれば、 __callStatic() メソッドの第一引数には「コールしようとしたメソッドの名前」すなわち 'get' が入り、第二引数には「メソッドに渡そうとしたパラメータが配列で」すなわち要素が function () { ... } だけからなる配列 [function () { ... }] が入ります。

__callStatic() メソッドが定義されているクラスは Illuminate\Support\Facades\Facade ですが、メソッドを呼び出し元のクラスは Illuminate\Support\Facades\Route です。

__callStatic() メソッドの中の static:: は今回の場合は Illuminate\Support\Facades\Route クラスに解決されるので、まずは Illuminate\Support\Facades\Route::getFacadeRoot() メソッドが実行されて返り値が $instance に代入され、例外処理をした後に $instance オブジェクトの get() メソッドが function () { ... } を引数として呼び出されます。

次は何をしますか?

  • $instance = static::getFacadeRoot() を実行した時に起きることを1段階深掘りします。
  • 深掘りする過程で、必要なら routes/web.php が読み込まれるまでに起きることを理解します。

Illuminate\Support\Facades\Facade::getFacadeRoot() の定義を見てみよう

vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.phpから抜粋
/**
 * Get the root object behind the facade.
 *
 * @return mixed
 */
public static function getFacadeRoot()
{
    return static::resolveFacadeInstance(static::getFacadeAccessor());
}

getFacadeRoot() メソッドの中の static:: は今回も Illuminate\Support\Facades\Route クラスに解決されます。 resolveFacadeInstance() メソッドは Illuminate\Support\Facades\Route クラスには定義されておらず、 Illuminate\Support\Facades\Facade クラスに定義されているのでそれを見てみましょう。

vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.phpから抜粋
/**
 * Resolve the facade root instance from the container.
 *
 * @param  object|string  $name
 * @return mixed
 */
protected static function resolveFacadeInstance($name)
{
    if (is_object($name)) {
        return $name;
    }

    if (isset(static::$resolvedInstance[$name])) {
        return static::$resolvedInstance[$name];
    }

    if (static::$app) {
        return static::$resolvedInstance[$name] = static::$app[$name];
    }
}

getFacadeAccessor() メソッドは Illuminate\Support\Facades\Route クラスに定義されているのでそれも見てみましょう。

vendor/laravel/framework/src/Illuminate/Support/Facades/Route.phpから抜粋
/**
 * Get the registered name of the component.
 *
 * @return string
 */
protected static function getFacadeAccessor()
{
    return 'router';
}

$instance = static::getFacadeRoot() を実行した時に何が起きますか?

↓ これを実行することは、

$instance = static::getFacadeRoot();

↓ これを実行することと同じと考えてよいです。

$instance = Illuminate\Support\Facades\Facade::resolveFacadeInstance('router');

$name = 'router' は文字列なので以下はスキップされます ↓

if (is_object($name)) {
    return $name;
}

static::$resolvedInstance[$name] が存在して NULL でない時には static::$resolvedInstance[$name] をそのまま返しているので、今回は static::$resolvedInstance[$name] が存在しないか NULL でない時のことを考えます。この場合は以下の処理が行われます ↓

  1. static::$app[$name] を取得して static::$resolvedInstance[$name] に代入します。
  2. static::resolveFacadeInstance()static::$resolvedInstance[$name] を返します。
  3. static::getFacadeRoot() はそのままそれを返します。
  4. Illuminate\Support\Facades\Facade::__callStatic() の中の $instance にはそれがそのまま代入されます。

以上のステップの static:: は全て Illuminate\Support\Facades\Route クラスに解決されます。したがって Illuminate\Support\Facades\Route::$app['router'] の中身がわかれば return $instance->$method(...$args) を実行した時に何が起きるかを1段階深掘りすることができます。

次は何をしますか?

  • Illuminate\Support\Facades\Route::$app['router'] の中身を1段階深掘りします。
  • 深掘りする過程で、必要なら routes/web.php が読み込まれるまでに起きることを理解します。

Illuminate\Support\Facades\Route::$app には何が入っているのか調べよう

Illuminate\Support\Facades\Route クラスには $app というクラスプロパティは定義されていません。 Illuminate\Support\Facades\Route クラスの親クラスである Illuminate\Support\Facades\Facade クラスには $app というクラスプロパティが定義されているため、 Illuminate\Support\Facades\Route::$app はこちらを指しています。

vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.phpから抜粋
/**
 * The application instance being facaded.
 *
 * @var \Illuminate\Contracts\Foundation\Application
 */
protected static $app;

結論から言ってしまうと Illuminate\Support\Facades\Facade::$app には Illuminate\Foundation\Application クラスのシングルトンが入っています。 Illuminate\Support\Facades\Facade::$appIlluminate\Foundation\Application クラスのシングルトンが入るまでを厳密に追うのには時間がかかるので、気になった方が追いやすくなるように細部を省いてプロットしておきます。

public/index.php

bootstrap/app.php を読み込んで実行し、返り値を $app に代入しています。

public/index.phpから抜粋
/*
|--------------------------------------------------------------------------
| Turn On The Lights
|--------------------------------------------------------------------------
|
| We need to illuminate PHP development, so let us turn on the lights.
| This bootstraps the framework and gets it ready for use, then it
| will load up this application so that we can run it and send
| the responses back to the browser and delight our users.
|
*/

$app = require_once __DIR__.'/../bootstrap/app.php';

bootstrap/app.php

$app には Illuminate\Foundation\Application クラスのインスタンスが入ります。

bootstrap/app.phpから抜粋
/*
|--------------------------------------------------------------------------
| Create The Application
|--------------------------------------------------------------------------
|
| The first thing we will do is create a new Laravel application instance
| which serves as the "glue" for all the components of Laravel, and is
| the IoC container for the system binding all of the various parts.
|
*/

$app = new Illuminate\Foundation\Application(
    $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);

↓ こんな設定をしています。

  • $app が「 Illuminate\Contract\Http\Kernel インターフェースを実装したクラスのインスタンスを作れ」と言われたら、 $appApp\Http\Kernel クラスのインスタンスを作る。
  • App\Http\Kernel クラスのインスタンスは1つしか作られない。すなわちシングルトンである。
bootstrap/app.phpから抜粋
/*
|--------------------------------------------------------------------------
| Bind Important Interfaces
|--------------------------------------------------------------------------
|
| Next, we need to bind some important interfaces into the container so
| we will be able to resolve them when needed. The kernels serve the
| incoming requests to this application from both the web and CLI.
|
*/

$app->singleton(
    Illuminate\Contracts\Http\Kernel::class,
    App\Http\Kernel::class
);

public/index.php 再び

$kernel には App\Http\Kernel クラスのインスタンスが入ります。

public/index.phpから抜粋
/*
|--------------------------------------------------------------------------
| Run The Application
|--------------------------------------------------------------------------
|
| Once we have the application, we can handle the incoming request
| through the kernel, and send the associated response back to
| the client's browser allowing them to enjoy the creative
| and wonderful application we have prepared for them.
|
*/

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

App\Http\Kernel クラスの handle() メソッドを呼び出します。

public/index.phpから抜粋
$response = $kernel->handle(
    $request = Illuminate\Http\Request::capture()
);

Illuminate\Foundation\Http\Kernel

App\Http\Kernel クラスは Illuminate\Foundation\Http\Kernel クラスを継承しており、 handle() メソッドはこちらのクラスに定義されています。

vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.phpから抜粋
/**
 * Handle an incoming HTTP request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return \Illuminate\Http\Response
 */
public function handle($request)
{
    try {
        $request->enableHttpMethodParameterOverride();

        $response = $this->sendRequestThroughRouter($request);
    } catch (Throwable $e) {
        $this->reportException($e);

        $response = $this->renderException($request, $e);
    }

    $this->app['events']->dispatch(
        new RequestHandled($request, $response)
    );

    return $response;
}

$request->enableHttpMethodParameterOverride(); はすっ飛ばして $response = $this->sendRequestThroughRouter($request) を深掘りします。

vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.phpから抜粋
/**
 * Send the given request through the middleware / router.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return \Illuminate\Http\Response
 */
protected function sendRequestThroughRouter($request)
{
    $this->app->instance('request', $request);

    Facade::clearResolvedInstance('request');

    $this->bootstrap();

    return (new Pipeline($this->app))
                ->send($request)
                ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
                ->then($this->dispatchToRouter());
}

いろいろすっ飛ばして $this->bootstrap(); を深掘りします。

vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.phpから抜粋
/**
 * Bootstrap the application for HTTP requests.
 *
 * @return void
 */
public function bootstrap()
{
    if (! $this->app->hasBeenBootstrapped()) {
        $this->app->bootstrapWith($this->bootstrappers());
    }
}

条件分岐はすっ飛ばして $this->app->bootstrapWith($this->bootstrappers()); を深掘りします。まずは Illuminate\Foundation\Http\Kernel クラスの bootstrappers() メソッドから読みます。

vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.phpから抜粋
/**
 * Get the bootstrap classes for the application.
 *
 * @return array
 */
protected function bootstrappers()
{
    return $this->bootstrappers;
}

$this->bootstrappersIlluminate\Foundation\Http\Kernel クラスに定義されています。

vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.phpから抜粋
/**
 * The bootstrap classes for the application.
 *
 * @var array
 */
protected $bootstrappers = [
    \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
    \Illuminate\Foundation\Bootstrap\LoadConfiguration::class,
    \Illuminate\Foundation\Bootstrap\HandleExceptions::class,
    \Illuminate\Foundation\Bootstrap\RegisterFacades::class,
    \Illuminate\Foundation\Bootstrap\RegisterProviders::class,
    \Illuminate\Foundation\Bootstrap\BootProviders::class,
];

Illuminate\Foundation\Bootstrap\RegisterFacades

Illuminate\Foundation\Bootstrap\RegisterFacades クラスは小さいので貼ってしまします。

vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/RegisterFacades.php
<?php

namespace Illuminate\Foundation\Bootstrap;

use Illuminate\Contracts\Foundation\Application;
use Illuminate\Foundation\AliasLoader;
use Illuminate\Foundation\PackageManifest;
use Illuminate\Support\Facades\Facade;

class RegisterFacades
{
    /**
     * Bootstrap the given application.
     *
     * @param  \Illuminate\Contracts\Foundation\Application  $app
     * @return void
     */
    public function bootstrap(Application $app)
    {
        Facade::clearResolvedInstances();

        Facade::setFacadeApplication($app);

        AliasLoader::getInstance(array_merge(
            $app->make('config')->get('app.aliases', []),
            $app->make(PackageManifest::class)->aliases()
        ))->register();
    }
}

Illuminate\Support\Facades\Facade

Illuminate\Support\Facades\Facade クラスの setFacadeApplication() メソッドの定義も貼っておきます。

vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.phpから抜粋
/**
 * Set the application instance.
 *
 * @param  \Illuminate\Contracts\Foundation\Application  $app
 * @return void
 */
public static function setFacadeApplication($app)
{
    static::$app = $app;
}

最後に Illuminate\Foundation\Application クラスの bootstrapWith() メソッドを読めば全部繋がります。

Illuminate\Foundation\Application

vendor/laravel/framework/src/Illuminate/Foundation/Application.phpから抜粋
/**
 * Run the given array of bootstrap classes.
 *
 * @param  string[]  $bootstrappers
 * @return void
 */
public function bootstrapWith(array $bootstrappers)
{
    $this->hasBeenBootstrapped = true;

    foreach ($bootstrappers as $bootstrapper) {
        $this['events']->dispatch('bootstrapping: '.$bootstrapper, [$this]);

        $this->make($bootstrapper)->bootstrap($this);

        $this['events']->dispatch('bootstrapped: '.$bootstrapper, [$this]);
    }
}

次は何をしますか?

  • Illuminate\Support\Facades\Route::$app['router'] の中身をもう1段階深掘りします。
  • 深掘りする過程で、必要なら routes/web.php が読み込まれるまでに起きることを理解します。

Illuminate\Support\Facades\Route::$app['router'] には何が入っているのか調べよう

$app はオブジェクトなのに、配列のように $app['router'] という記述がされています。まずはこれがどうやって動くのかを調べます。

Illuminate\Foundation\Application クラスは Illuminate\Container\Container クラスを継承しており、 Illuminate\Container\Container クラスは ArrayAccess というインターフェースを実装しています。 ArrayAccessSPL(Standard PHP Library)で定義されているインターフェースの1つ で、次の4つのメソッドを定義してやることでオブジェクトに対して配列のようなアクセスをすることが可能になります。

  • offsetExists()
  • offsetGet()
  • offsetSet()
  • offsetUnset()

Illuminate\Container\Container クラスの offsetGet() メソッド

$app['router'] を取得しようとしたときは $app に入っているオブジェクトの offsetGet() メソッドが呼び出されます。これは Illuminate\Container\Container クラスに定義されています。

vendor/laravel/framework/src/Illuminate/Container/Container.phpから抜粋
/**
 * Get the value at a given offset.
 *
 * @param  string  $key
 * @return mixed
 */
public function offsetGet($key)
{
    return $this->make($key);
}

Illuminate\Foundation\Application クラスの make() メソッド

offsetGet() メソッドを呼び出したオブジェクト $appIlluminate\Foundation\Application クラスのインスタンスなので、まずは Illuminate\Foundation\Application クラスに定義されている make() メソッドが呼ばれます。

vendor/laravel/framework/src/Illuminate/Foundation/Application.phpから抜粋
/**
 * Resolve the given type from the container.
 *
 * @param  string  $abstract
 * @param  array  $parameters
 * @return mixed
 */
public function make($abstract, array $parameters = [])
{
    $this->loadDeferredProviderIfNeeded($abstract = $this->getAlias($abstract));

    return parent::make($abstract, $parameters);
}

Illuminate\Container\Container クラスの make() メソッド

返される値は parent::make($abstract, $parameters) なので、 $this->loadDeferredProviderIfNeeded($abstract = $this->getAlias($abstract)); は飛ばして Illuminate\Container\Container クラスの make() メソッドを貼ります。

vendor/laravel/framework/src/Illuminate/Container/Container.phpから抜粋
/**
 * Resolve the given type from the container.
 *
 * @param  string  $abstract
 * @param  array  $parameters
 * @return mixed
 *
 * @throws \Illuminate\Contracts\Container\BindingResolutionException
 */
public function make($abstract, array $parameters = [])
{
    return $this->resolve($abstract, $parameters);
}

Illuminate\Foundation\Application クラスの resolve() メソッド

offsetGet() メソッドを呼び出したオブジェクト $appIlluminate\Foundation\Application クラスのインスタンスなので、戻って Illuminate\Foundation\Application クラスに定義されている resolve() メソッドが呼ばれます。

vendor/laravel/framework/src/Illuminate/Foundation/Application.phpから抜粋
/**
 * Resolve the given type from the container.
 *
 * @param  string  $abstract
 * @param  array  $parameters
 * @param  bool  $raiseEvents
 * @return mixed
 */
protected function resolve($abstract, $parameters = [], $raiseEvents = true)
{
    $this->loadDeferredProviderIfNeeded($abstract = $this->getAlias($abstract));

    return parent::resolve($abstract, $parameters, $raiseEvents);
}

Illuminate\Container\Container クラスの resolve() メソッド

返される値は parent::resolve($abstract, $parameters, $raiseEvents) なので、 $this->loadDeferredProviderIfNeeded($abstract = $this->getAlias($abstract)); は飛ばして Illuminate\Container\Container クラスの resolve() メソッドを貼ります。

vendor/laravel/framework/src/Illuminate/Container/Container.phpから抜粋
/**
 * Resolve the given type from the container.
 *
 * @param  string  $abstract
 * @param  array  $parameters
 * @param  bool  $raiseEvents
 * @return mixed
 *
 * @throws \Illuminate\Contracts\Container\BindingResolutionException
 */
protected function resolve($abstract, $parameters = [], $raiseEvents = true)
{
    $abstract = $this->getAlias($abstract);

    $concrete = $this->getContextualConcrete($abstract);

    $needsContextualBuild = ! empty($parameters) || ! is_null($concrete);

    // If an instance of the type is currently being managed as a singleton we'll
    // just return an existing instance instead of instantiating new instances
    // so the developer can keep using the same objects instance every time.
    if (isset($this->instances[$abstract]) && ! $needsContextualBuild) {
        return $this->instances[$abstract];
    }

    $this->with[] = $parameters;

    if (is_null($concrete)) {
        $concrete = $this->getConcrete($abstract);
    }

    // We're ready to instantiate an instance of the concrete type registered for
    // the binding. This will instantiate the types, as well as resolve any of
    // its "nested" dependencies recursively until all have gotten resolved.
    if ($this->isBuildable($concrete, $abstract)) {
        $object = $this->build($concrete);
    } else {
        $object = $this->make($concrete);
    }

    // If we defined any extenders for this type, we'll need to spin through them
    // and apply them to the object being built. This allows for the extension
    // of services, such as changing configuration or decorating the object.
    foreach ($this->getExtenders($abstract) as $extender) {
        $object = $extender($object, $this);
    }

    // If the requested type is registered as a singleton we'll want to cache off
    // the instances in "memory" so we can return it later without creating an
    // entirely new instance of an object on each subsequent request for it.
    if ($this->isShared($abstract) && ! $needsContextualBuild) {
        $this->instances[$abstract] = $object;
    }

    if ($raiseEvents) {
        $this->fireResolvingCallbacks($abstract, $object);
    }

    // Before returning, we will also set the resolved flag to "true" and pop off
    // the parameter overrides for this build. After those two things are done
    // we will be ready to return back the fully constructed class instance.
    $this->resolved[$abstract] = true;

    array_pop($this->with);

    return $object;
}

ここで頭が爆発したのでレジュメはここまでです。輪講までに理解できたらその場で話すかもです。

23
28
3

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
23
28