Laravel 7.4のコードを読む

Laravel 7.4のコードを読む。

```
$ php artisan -V
Laravel Framework 7.4.0
```

# path/public/index.php 
httpリクエストのエントリーポイントのindex.phpを追う。

```
define('LARAVEL_START', microtime(true));
```

初めに `LARAVEL_START` という定数が作成される。値は実行時のUnixタイムスタンプ(マイクロ秒単位/float型)。
計測で使える。(phpドキュメントによると計測用ならmicrotime()ではなくhrtime()を使った方が良いらしい)
artisanのエントリーポイントでも同様の処理がある。

```
require __DIR__.'/vendor/autoload.php';
```
続いてautoloadを読み込む。

```
$app = require_once __DIR__.'/bootstrap/app.php';
```
続いてapp.phpを読み込む。app.phpはlaravel本体の起動を行う。
autoloadはrequireで読み込んだのにappはrequire_onceになってる。本体の起動は絶対1回しかやりたくないからrequire_onceを使うのかな。

```
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
```
続いて$appのサービスコンテナの機能を使ってKernelインターフェースの実クラスを読み込む。
app.phpでバインドすることでKernelの動作を実装者サイドで決められるようにしてるのか。
`$app->make`の関数は良く使うので覚えておこう。
ちなみにlaravelではインターフェースのことをConstracts(制約)と読ぶ。
C#等の言語だとインターフェースは頭にIを付けてIKernel::classになるけどlaravelではIは付けないようだ。

```
$response = $kernel->handle(
    $request = Illuminate\Http\Request::capture()
);

↓つまりこういうこと？
$request = Illuminate\Http\Request::capture()
$response = $kernel->handle($request);
```
続いてrequestとresponseの作成を行う。handle関数引数で$request宣言するのはなぜだろう。

```
$response->send();
```
続いてheaderとcontentを書き込む。

```
$kernel->terminate($request, $response);
```
最後に終了処理を行う。内部ではterminateMiddlewareの実行やapplicationのterminateを実行する。

# bootstrap/app.php
index.phpで読み込まれたapp.phpを追う。

```
$app = new Illuminate\Foundation\Application(
    $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);
```
まずlaravel本体のApplicationクラスをインスタンス化する。
ApplicationはbasePathを引数に渡せる。環境変数APP_BASE_PATHを、無ければ `dirname(__DIR__) = bootstrapフォルダの親フォルダ` が使われる。
$appはapp.phpだと思っていたのだけどApplicationインスタンスだったのね。

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

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

$app->singleton(
    Illuminate\Contracts\Debug\ExceptionHandler::class,
    App\Exceptions\Handler::class
);
```
続いてKernelのBindを行う。
app.phpはhttpやconsole等の異なるエントリーポイントからも呼ばれるためアプリケーション全体で最低限必要なbindのみを行うようだ。
特定のエントリーポイントのみに関連する処理は行わないよう注意したい。
ちなみにGAE/SE環境にlaravelアプリケーションをdeployする際はここに`$app->useStoragePath(env('APP_STORAGE', base_path() . '/storage'));` を追加する。


# Illuminate\Foundation\Application
laravelアプリケーションの本体クラスを追う。
Illuminate\Foundation名前空間に存在する。ここには他にAliasLoader.php, helper.php, Mix.php等が存在する。
約1,300行なのでそこまで量は多くない。

## Applicationの継承
まずは継承を見る。

```
class Application extends Container implements ApplicationContract, CachesConfiguration, CachesRoutes, HttpKernelInterface
```

### Container
`Illuminate\Container\Container.php`
サービスコンテナを管理するクラス。
$app->make()の処理はこれが担当している。後ほど詳しく見る。

### ApplicationContract
Illuminate\Contracts\Foundation\Application.php
Applicationのインターフェース。
- version関数
- パス関連関数(basePathやbootstrapPath等)
- 環境変数関数
- provider関連関数
- boot関数
- locale関数
- terminate関数

### CachesConfiguration
Illuminate\Contracts\Foundation\CachesConfiguration.php
application configurationのキャッシュを管理するインターフェースのようだけど、何をしているんだろう。
- configurationIsCached
- getCachedConfigPath
- getCachedServicesPath

### CachesRoutes
Illuminate\Contracts\Foundation\CachesRoutes.php
routeファイルのキャッシュを管理する。
- routesAreCached
- getCachedRoutesPath

### HttpKernelInterface
Symfony\Component\HttpKernel\HttpKernelInterface.php
これはIlluminate\ContractsではなくSymfonyのもの。
requestをresponseに変換する関数のみ定義されてる。
- handle

## Applicationのコンストラクタ
```
     */
    public function __construct($basePath = null)
    {
        if ($basePath) {
            $this->setBasePath($basePath);
        }

        $this->registerBaseBindings();
        $this->registerBaseServiceProviders();
        $this->registerCoreContainerAliases();
    }
```

basePathを引数に受け取る。
basePathとはプロジェクトのルートパスのこと。
basePathがnull許容なのはなぜだろう。。。

```
    public function setBasePath($basePath)
    {
        $this->basePath = rtrim($basePath, '\/');

        $this->bindPathsInContainer();

        return $this;
    }

    protected function bindPathsInContainer()
    {
        $this->instance('path', $this->path());
        $this->instance('path.base', $this->basePath());
        $this->instance('path.lang', $this->langPath());
        $this->instance('path.config', $this->configPath());
        省略
```

setBasePathでサービスコンテナにpathをbindしてる。(でもこのタイミングではbasePath以外は実装者はpathをセットしていないからデフォルト値が入る)

```
    protected function registerBaseBindings()
    {
        static::setInstance($this);

        $this->instance('app', $this);

        $this->instance(Container::class, $this);
        $this->singleton(Mix::class);

        $this->instance(PackageManifest::class, new PackageManifest(
            new Filesystem, $this->basePath(), $this->getCachedPackagesPath()
        ));
    }
```
根幹的なクラスのbindingを行う。
Applicationクラスは `$app->make('app')` でも `$app->make(Container::class)` でも取得できるようだ。
PackageManifestとはなんだろう。


```
    protected function registerBaseServiceProviders()
    {
        $this->register(new EventServiceProvider($this));
        $this->register(new LogServiceProvider($this));
        $this->register(new RoutingServiceProvider($this));
    }
```
根幹的なサービスプロバイダーを登録する。
- EventServiceProvider : eventDispatcherをコンテナに登録
- LogServiceProvider : LogManagerをコンテナに登録
- RoutingServiceProvider : routesやurlをコンテナに登録


```
    public function registerCoreContainerAliases()
    {
        foreach ([
            'app'                  => [self::class, \Illuminate\Contracts\Container\Container::class, \Illuminate\Contracts\Foundation\Application::class, \Psr\Container\ContainerInterface::class],
            'auth'                 => [\Illuminate\Auth\AuthManager::class, \Illuminate\Contracts\Auth\Factory::class],
            'auth.driver'          => [\Illuminate\Contracts\Auth\Guard::class],
            'blade.compiler'       => [\Illuminate\View\Compilers\BladeCompiler::class],
            省略
            ] as $key => $aliases) {
            foreach ($aliases as $alias) {
                $this->alias($key, $alias);
            }
        }

```
根幹的なファサードのaliasを登録する。
サービスコンテナに登録したクラスをファサード経由でアクセスするにはファサードのusingが必要だけど、aliasに登録することでファサードのusingなしに `\App::version();` のように記述できるようになる。
ide_helperを使えばIDE上でコード補完できるようになる。