1. 程式人生 > >Laravel原始碼解析一 【請求的生命週期】

Laravel原始碼解析一 【請求的生命週期】

不BB,直接開始。
看一個框架的原始碼,第一步我們先看入口檔案。
laravel的入口檔案在public目錄下的index.php

require __DIR__.'/../bootstrap/autoload.php';

這玩意是載入composer的一些東西,自動載入有需要的類。具體的也不多說,主要是我還沒玩會這玩意。
接著看

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

這裡要看bootstrap目錄下的app.php檔案
這個檔案裡映入眼簾的就是

$app = new Illuminate\Foundation\Application(
    realpath(__DIR__
.'/../') );

好吧。new一個application出來。那麼我們找到Illuminate\Foundation\Application這個檔案

public function __construct($basePath = null)
    {
        $this->registerBaseBindings();

        $this->registerBaseServiceProviders();

        $this->registerCoreContainerAliases();

        if ($basePath) {
            $this
->setBasePath($basePath); } }

new application時的建構函式長這個樣子。寫到這的時候,我突然覺得加個序號可能會比較好。

(一) new Application的過程

1.1先是註冊基本繫結,也就是 $this->registerBaseBindings();這個方法裡的內容

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

        $this->instance('app'
, $this); $this->instance('Illuminate\Container\Container', $this); }

巨簡單的過程,就是把例項化的的application 賦值給app和Illuminate\Container\Container

1.2註冊基本的服務提供者。$this->registerBaseServiceProviders();

protected function registerBaseServiceProviders()
    {
        $this->register(new EventServiceProvider($this));

        $this->register(new RoutingServiceProvider($this));
    }

這裡通過名字可以感覺出是註冊了事件服務提供者和路由服務提供者

1.3註冊核心類名的別名$this->registerCoreContainerAliases();

public function registerCoreContainerAliases()
    {
        $aliases = [
            'app'                  => ['Illuminate\Foundation\Application', 'Illuminate\Contracts\Container\Container', 'Illuminate\Contracts\Foundation\Application'],
            'auth'                 => ['Illuminate\Auth\AuthManager', 'Illuminate\Contracts\Auth\Factory'],
            'auth.driver'          => ['Illuminate\Contracts\Auth\Guard'],
            'blade.compiler'       => ['Illuminate\View\Compilers\BladeCompiler'],
            'cache'                => ['Illuminate\Cache\CacheManager', 'Illuminate\Contracts\Cache\Factory'],
            'cache.store'          => ['Illuminate\Cache\Repository', 'Illuminate\Contracts\Cache\Repository'],
            'config'               => ['Illuminate\Config\Repository', 'Illuminate\Contracts\Config\Repository'],
            'cookie'               => ['Illuminate\Cookie\CookieJar', 'Illuminate\Contracts\Cookie\Factory', 'Illuminate\Contracts\Cookie\QueueingFactory'],
            'encrypter'            => ['Illuminate\Encryption\Encrypter', 'Illuminate\Contracts\Encryption\Encrypter'],
            'db'                   => ['Illuminate\Database\DatabaseManager'],
            'db.connection'        => ['Illuminate\Database\Connection', 'Illuminate\Database\ConnectionInterface'],
            'events'               => ['Illuminate\Events\Dispatcher', 'Illuminate\Contracts\Events\Dispatcher'],
            'files'                => ['Illuminate\Filesystem\Filesystem'],
            'filesystem'           => ['Illuminate\Filesystem\FilesystemManager', 'Illuminate\Contracts\Filesystem\Factory'],
            'filesystem.disk'      => ['Illuminate\Contracts\Filesystem\Filesystem'],
            'filesystem.cloud'     => ['Illuminate\Contracts\Filesystem\Cloud'],
            'hash'                 => ['Illuminate\Contracts\Hashing\Hasher'],
            'translator'           => ['Illuminate\Translation\Translator', 'Symfony\Component\Translation\TranslatorInterface'],
            'log'                  => ['Illuminate\Log\Writer', 'Illuminate\Contracts\Logging\Log', 'Psr\Log\LoggerInterface'],
            'mailer'               => ['Illuminate\Mail\Mailer', 'Illuminate\Contracts\Mail\Mailer', 'Illuminate\Contracts\Mail\MailQueue'],
            'auth.password'        => ['Illuminate\Auth\Passwords\PasswordBrokerManager', 'Illuminate\Contracts\Auth\PasswordBrokerFactory'],
            'auth.password.broker' => ['Illuminate\Auth\Passwords\PasswordBroker', 'Illuminate\Contracts\Auth\PasswordBroker'],
            'queue'                => ['Illuminate\Queue\QueueManager', 'Illuminate\Contracts\Queue\Factory', 'Illuminate\Contracts\Queue\Monitor'],
            'queue.connection'     => ['Illuminate\Contracts\Queue\Queue'],
            'queue.failer'         => ['Illuminate\Queue\Failed\FailedJobProviderInterface'],
            'redirect'             => ['Illuminate\Routing\Redirector'],
            'redis'                => ['Illuminate\Redis\Database', 'Illuminate\Contracts\Redis\Database'],
            'request'              => ['Illuminate\Http\Request', 'Symfony\Component\HttpFoundation\Request'],
            'router'               => ['Illuminate\Routing\Router', 'Illuminate\Contracts\Routing\Registrar'],
            'session'              => ['Illuminate\Session\SessionManager'],
            'session.store'        => ['Illuminate\Session\Store', 'Symfony\Component\HttpFoundation\Session\SessionInterface'],
            'url'                  => ['Illuminate\Routing\UrlGenerator', 'Illuminate\Contracts\Routing\UrlGenerator'],
            'validator'            => ['Illuminate\Validation\Factory', 'Illuminate\Contracts\Validation\Factory'],
            'view'                 => ['Illuminate\View\Factory', 'Illuminate\Contracts\View\Factory'],
        ];

        foreach ($aliases as $key => $aliases) {
            foreach ($aliases as $alias) {
                $this->alias($key, $alias);
            }
        }
    }

這個方法更簡單,就是一個別名陣列,然後通過for迴圈呼叫$this->alias()給Application類的父類Container裡的aliases數組裡。

1.4設定基本路徑,我們在new Application時傳入的 realpath(DIR.’/../’)這個引數賦值給基本路徑

(二)註冊共享的Kernel和異常處理器

我們的app也new好了,我們接著app.php裡往下走可以看到

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

這三個具體幹嘛的我們以後分析,然後app.php最後返回的是app例項

(三)處理請求和響應

app.php檔案執行完以後回到index.php 可以看到

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

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

$response->send();

$kernel->terminate($request, $response);

3.1解析Illuminate\Contracts\Http\Kernel,例項化App\Http\Kernel

3.2例項化後的kernel處理本次請求。這裡$kernel->handle()傳入的引數是一個request。
這裡的request是經過Symfony封裝的請求物件。講道理看到這的時候我有點懵逼。臥槽,我剛開始學laravel,還沒整明白呢,就又多了一個Symfony要學,至少得了解怎麼封裝的請求物件。好煩呀。。。

3.3是將請求處理後的返回結果傳送到瀏覽器裡

3.4處理繼承自TerminableMiddleware介面的中介軟體(Session)並結束應用生命週期。

以上就是laravel框架裡執行一次請求所要經歷的生命週期。
具體的如何註冊如何載入如何封裝請求,我會隨著自己知識的積累和分析原始碼來做出解答。
順便,我也是剛開始學習laravel。一起加油!