본문 바로가기
Framework/Laravel Framework

[Laravel] Request LifeCycle (3)

by 원동호 2021. 9. 7.

2021.07.09 - [Framework/Laravel Framework] - [Laravel] Request LifeCycle (1)

2021.07.16 - [Framework/Laravel Framework] - [Laravel] Request LifeCycle (2)

 

첫 포스팅에서는 Laravel Request Lifecycle을 간단하게 구성도로 알아 보았고 두번째 포스팅에서는 Compser의 autoloading에 대해서 알아 보았다.

 

이번 포스팅에서는 라라밸 애플리케이션의 bootstrapping 과정을 알아 보겠다.

 

public/index.php

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

위 스크립트가 라라벨 애플리케이션의 핵심이며 서비스 컨테이너 인스턴스를 생성 한다.

 

bootstrap/app.php

<?php


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

$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
);

return $app;

위 코드를 살펴보면

 

1. Application class에서 새로운 인스턴스(서비스 컨테이너)를 생성한다.

-> 위 클래스는 Laravel 버전, 컨테이너, 경로 등이 설정되어 있고 Container을 extends 한다.

2. HTTP Kernel을 생성한다.

3. Console Kernel을 생성한다.

4. 생성한 인스턴스를 반환한다.

 

첫번째로 Application Class를 살펴보겠다.

 

vendor/laravel/framework/src/Illuminate/Foundation/Application.php

    public function __construct($basePath = null)
    {
        if ($basePath) {
            // 1.
            $this->setBasePath($basePath);
        }
        // 2.
        $this->registerBaseBindings();
        // 3.
        $this->registerBaseServiceProviders();
        // 4.
        $this->registerCoreContainerAliases();
    }

위 클래스를 서비스 컨테이너(App Container)라고 한다. 첫번째로 App의 기본 경로를 등록하고 App Container에 바인딩하고 Service Provider을 App Container에 등록하고, coreContainer 별칭을 App Container에 등록한다.

 

첫번째 메소드부터 알아보겠다.

 

1. 컨테이너에 경로 등록

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());
        $this->instance('path.public', $this->publicPath());
        $this->instance('path.storage', $this->storagePath());
        $this->instance('path.database', $this->databasePath());
        $this->instance('path.resources', $this->resourcePath());
        $this->instance('path.bootstrap', $this->bootstrapPath());
}

setBasePath($basePath) 메소드는 애플리케이션 경로, config 경로, storage경로 등 관련 경로를 컨테이너에 등록한다.

 

$this->instance() 메소드에 대해 알아보자. Application Class가 Container Class를 상속하고 있기 때문에 Container Class로 이동해보자.

 

vendor/laravel/framework/src/Illuminate/Foundation/Container/Container.php

/**
     * Register an existing instance as shared in the container.
     *
     * @param  string  $abstract
     * @param  mixed  $instance
     * @return mixed
     */
    public function instance($abstract, $instance)
    {
        $this->removeAbstractAlias($abstract);

        $isBound = $this->bound($abstract);

        unset($this->aliases[$abstract]);

        // We'll check to determine if this type has been bound before, and if it has
        // we will fire the rebound callbacks registered with the container and it
        // can be updated with consuming classes that have gotten resolved here.
        $this->instances[$abstract] = $instance;

        if ($isBound) {
            $this->rebound($abstract);
        }

        return $instance;
    }

다음으로 $this->removeAbstractAlias($abstract) 함수가 실행된다. 여기서 전달된 인자는 경로 이며 이 함수에서는

Application instance의 aliases 변수에서 캐시를 지운다. 값이 존재 하지 않으면 return, 값이 존재 하는 경우 배열을 탐색하여 삭제한다.

/**
     * Remove an alias from the contextual binding alias cache.
     *
     * @param  string  $searched
     * @return void
     */
protected function removeAbstractAlias($searched)
    {
        if (! isset($this->aliases[$searched])) {
            return;
        }

        foreach ($this->abstractAliases as $abstract => $aliases) {
            foreach ($aliases as $index => $alias) {
                if ($alias == $searched) {
                    unset($this->abstractAliases[$abstract][$index]);
                }
            }
        }
    }

 

로그로 확인해보면 instances 배열에 경로가 등록된걸 확인할 수 있다.

^ Illuminate\Foundation\Application {#2 ▼
  #basePath: "D:\laravel"
  #hasBeenBootstrapped: false
  #booted: false
 .
 .
  #instances: array:9 [▼
    "path" => "D:\laravel\app"
    "path.base" => "D:\laravel"
    "path.lang" => "D:\laravel\resources\lang"
    "path.config" => "D:\laravel\config"
    "path.public" => "D:\laravel\public"
    "path.storage" => "D:\laravel\storage"
    "path.database" => "D:\laravel\database"
    "path.resources" => "D:\laravel\resources"
    "path.bootstrap" => "D:\laravel\bootstrap"
  ]
 .
 .
}

 

2. 컨테이너에 자신을 등록

construnct의 2번째 함수인 $this->registerBaseBindings();에 대해서 알아보자.

/**
     * Register the basic bindings into the container.
     *
     * @return void
     */
    protected function registerBaseBindings()
    {

        static::setInstance($this);
        $this->instance('app', $this);

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

        $this->singleton(PackageManifest::class, function () {
            return new PackageManifest(
                new Filesystem, $this->basePath(), $this->getCachedPackagesPath()
            );
        });
    }

처음으로 static::setInstance($this)가 실행되고 $this(Application Class)는 $instance에 정적으로 할당한다.

(Singleton)

 

vendor/laravel/framework/src/Illuminate/Foundation/Container/Container.php

    /**
     * Set the shared instance of the container.
     *
     * @param  \Illuminate\Contracts\Container\Container|null  $container
     * @return \Illuminate\Contracts\Container\Container|static
     */
    public static function setInstance(ContainerContract $container = null)
    {
        return static::$instance = $container;
    }

 

그런다음 app, Container::class 를 자체적으로 바인딩 하고 Mix::class 및 PackageManifest클래스가 나타내는 패키지 로더를 바인딩하는 특정 작업도 수행한다.

 

registerBaseBindings() 함수에 대해서 아직 제대로 확인하지 않은 점이 많아서 시간이 나면 코드 분석 후 포스팅을 수정해야 할 것 같다. 다음 포스팅에서는 $this->registerBaseServiceProviders() , $this->registerCoreContainerAliases() 함수에 대해서 살펴 보겠다.

댓글0