Рубрики
Uncategorized

Анализ исходного кода начальной загрузки учебных заметок Laravel

Автор оригинала: David Wong.

Примечание: Laravel передает запрос Конвейер Перед отправкой промежуточному программному обеспечению и маршрутизатору, также была запущена начальная загрузка. В этой статье в основном изучался соответствующий исходный код, рассматривалась конкретная работа программы запуска Laravel и делился личным исследовательским центром, надеясь быть полезным другим. Laravel загружает загрузчик композитора, когда он вводит индекс. php : Составитель учебных заметок Laravel загружается автоматически, а затем создает приложение: Контейнер IoC создает экземпляр исходного кода для учебных заметок Laravel, получает созданный объект приложения, затем анализирует службу ядра из контейнера и реализует реализацию запроса. Запросите создание экземпляра, давайте поговорим об этом в следующий раз. Затем перейдите к операции начальной загрузки для запуска программы Затем конвейер отправляется в промежуточное программное обеспечение: Laravel для анализа исходного кода промежуточного программного обеспечения для изучения заметок, а затем с помощью сопоставления маршрутизации для поиска действия операции для запроса (позже в чате) генерируется объект ответа

Среда разработки: Laravel 5.3 + PHP7 + OS X 10.11

Я говорил о разборе исходного кода промежуточного программного обеспечения в заметках по обучению Laravel. SendRequestThroughRouter () в ядре обрабатывает Запрос и отправляет Запрос в конвейер промежуточному программному обеспечению и маршрутизатору для просмотра исходного кода:

protected function sendRequestThroughRouter($request)
    {
        $this->app->instance('request', $request);

        Facade::clearResolvedInstance('request');

        /* The bootstrap () function of each bootstrapper in $bootstrappers is executed in turn, and several preparations are made:
        1. DetectEnvironment for Environmental Detection
        2. Configuration Load Configuration
        3. Logging configuration ConfigureLogging
        4. HandleException for exception handling
        5. Register Facades Register Facades
        6. Register Providers Register Providers
        7. Start Providers BootProviders
         protected $bootstrappers = [
            'Illuminate\Foundation\Bootstrap\DetectEnvironment',
            'Illuminate\Foundation\Bootstrap\LoadConfiguration',
            'Illuminate\Foundation\Bootstrap\ConfigureLogging',
            'Illuminate\Foundation\Bootstrap\HandleExceptions',
            'Illuminate\Foundation\Bootstrap\RegisterFacades',
            'Illuminate\Foundation\Bootstrap\RegisterProviders',
            'Illuminate\Foundation\Bootstrap\BootProviders',
        ];*/
        $this->bootstrap();

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

Существует еще один шаг для начальной загрузки (), прежде чем запрос будет отправлен промежуточному программному обеспечению по конвейеру, который является Программой запуска Посмотрите исходный код начальной загрузки () в Http-ядре Illuminate Foundation:

protected $hasBeenBootstrapped = false;
    
    ...
    
    /**
     * Bootstrap the application for HTTP requests.
     *
     * @return void
     */
    public function bootstrap()
    {
        // Check if the program has been started
        if (! $this->app->hasBeenBootstrapped()) {
            $this->app->bootstrapWith($this->bootstrappers());
        }
    }
    
    public function hasBeenBootstrapped()
    {
        return $this->hasBeenBootstrapped;
    }
    
    protected function bootstrappers()
    {
        return $this->bootstrappers;
    }
    
    protected $bootstrappers = [
        'Illuminate\Foundation\Bootstrap\DetectEnvironment',
        'Illuminate\Foundation\Bootstrap\LoadConfiguration',
        'Illuminate\Foundation\Bootstrap\ConfigureLogging',
        'Illuminate\Foundation\Bootstrap\HandleExceptions',
        'Illuminate\Foundation\Bootstrap\RegisterFacades',
        'Illuminate\Foundation\Bootstrap\RegisterProviders',
        'Illuminate\Foundation\Bootstrap\BootProviders',
    ];

Как вы можете видеть из приведенного выше исходного кода, программа загрузится с () массивом $загрузчиков каждого загрузчика, посмотрите исходный код bootstrapWith () в контейнере:

    public function bootstrapWith(array $bootstrappers)
    {
        $this->hasBeenBootstrapped = true;

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

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

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

Сначала запустите ” перезагрузку:”. событие $bootstrapper, сообщите, что загрузчик будет запущен, затем сделайте ($bootstrapper) из контейнера и выполните метод bootstrapper () в $bootstrapper и, наконец, запустите событие: “загрузочный:”. $загрузчик, сообщите, что $загрузчик запущен нормально. Начальные загрузчики – это семь загрузчиков в массиве $bootstrappers. Посмотрите, что сделала программа для запуска.

1. Экологические испытания

Проверьте исходный код начальной загрузки () в среде обнаружения начальной загрузки Illuminate Foundation:

public function bootstrap(Application $app)
    {
        // Check whether bootstrap/cache/config.php cache file exists
        // PHP artisan config: cache to generate configuration caching files, is to config / all files in a cache file, improve performance
        // It is assumed that there is no cache configuration file
        if (! $app->configurationIsCached()) {
            $this->checkForSpecificEnvironmentFile($app);

            try {
                $env = $ENV; // debug added, empty at this time
                // Here, take out the value of the. env file and save it in $_ENV
                (new Dotenv($app->environmentPath(), $app->environmentFile()))->load();
                // Here the $_ENV array is valuable
                $env = $_ENV;
            } catch (InvalidPathException $e) {
                //
            }
        }
    }
    
    protected function checkForSpecificEnvironmentFile($app)
    {
        // Read the value of'APP_ENV'in the global variable of $_ENV, which is empty
        if (! env('APP_ENV')) {
            return;
        }

        $file = $app->environmentFile().'.'.env('APP_ENV'); // .env.local

        if (file_exists($app->environmentPath().'/'.$file)) {
            $app->loadEnvironmentFrom($file);
        }
    }

Основой экологического мониторинга является сохранение внутренней ценности. файл env в функцию \ Dotenv Dotenv:: load () глобальной переменной $_ENV, которая не детализирована. Вы можете просмотреть его с помощью отладки Xdebug:

2. Загрузка конфигурации

Загрузка конфигурации заключается в том, чтобы прочитать все значения конфигурации в папке config/, а затем сохранить их в объекте репозитория конфигурации Illuminate, в то время как обнаружение среды должно быть прочитано. Файл env хранится в глобальной переменной $_ENV. Конфигурация среды загрузки в основном заключается в использовании компонента Symfony Component Finder для поиска файлов. Посмотрите на конфигурацию загрузки. Вкл.:: исходный код начальной загрузки ():

public function bootstrap(Application $app)
    {        
        $items = [];
        // Check to see if config has a cache file, which is in bootstrap/cache/config.php
        // Generate caching files by PHP artisan config: cache command, package all configuration files under config / into one file, improve program execution speed
        // It is assumed that there are no cached files.
        if (file_exists($cached = $app->getCachedConfigPath())) {
            $items = require $cached;

            $loadedFromCache = true;
        }
        // Binding service'config', service is Illuminate Config Repository object
        $app->instance('config', $config = new Repository($items));

        if (! isset($loadedFromCache)) {
            // Load all config/*.php configuration files and store all configurations in the Repository object
            $this->loadConfigurationFiles($app, $config);
        }
        // Check the'APP_ENV'environment settings, which are generally'dev','stg','prd' three environments, namely'development','staging','production'.
        $app->detectEnvironment(function () use ($config) {
            return $config->get('app.env', 'production');
        });

        // Setting the time zone, $config ['app. timezone'] calls Repository:: get ('app. timezone'), because Repository implements ArrayAccess Interface.
        //'.'Syntax reading is implemented by Arr:: get (), which is a very useful method.
        date_default_timezone_set($config['app.timezone']);

        mb_internal_encoding('UTF-8');
    }

Загрузка файла конфигурации заключается в чтении файла/config/*.php и просмотре исходного кода:

protected function loadConfigurationFiles(Application $app, RepositoryContract $repository)
    {
        foreach ($this->getConfigurationFiles($app) as $key => $path) {
            // Store it in the Repository object and in the $items [] attribute with'key => value'
            $repository->set($key, require $path);
        }
    }
    
    protected function getConfigurationFiles(Application $app)
    {
        $files = [];
        // That's the'config/'path.
        $configPath = realpath($app->configPath());
        // Finder chain interface reads all config/*.php files, gets all file names, and then traverses them in turn
        foreach (Finder::create()->files()->name('*.php')->in($configPath) as $file) {
            $nesting = $this->getConfigurationNesting($file, $configPath);

            $files[$nesting.basename($file->getRealPath(), '.php')] = $file->getRealPath();
        }

        return $files;
    }

Вы можете отладить Xdebug, чтобы узнать, что возвращаемое значение $files представляет собой массив, подобный этому:

$files = [
        'app'=>'/vagrant/config/app.php', //absolute path of file
        'auth'         => 'vagrant/config/auth.php',
        'broadcasting' => '/vagrant/config/broadcasting.php',
        'cache'        => '/vagrant/config/cache.php',
        'compile'      => 'vagrant/config/compile.php',
        'database'     => '/vagrant/config/databse.php',
        'filesystems'  => '/vagrant/config/filesystems.php',
        'mail'         => '/vagrant/config/mail.php',
        'queue'        => '/vagrant/config/queue.php',
        'services'     => '/vagrant/config/services.php',
        'session'      => '/vagrant/config/session.php',
        'view'         => '/vagrant/config/view.php',
    ];

Затем, с помощью метода приложения Среда обнаружения (), значение app.env равно app.php в env Значение извлекается и сохраняется в атрибуте $env объекта приложения:

    public function detectEnvironment(Closure $callback)
    {
        $args = isset($_SERVER['argv']) ? $_SERVER['argv'] : null;

        return $this['env'] = (new EnvironmentDetector())->detect($callback, $args);
    }
    
    public function detect(Closure $callback, $consoleArgs = null)
    {
        if ($consoleArgs) {
            return $this->detectConsoleEnvironment($callback, $consoleArgs);
        }

        return $this->detectWebEnvironment($callback);
    }
    
    protected function detectWebEnvironment(Closure $callback)
    {
        return call_user_func($callback);
    }

Таким образом, значение атрибута $env сохраняется при проверке атрибута. App:: environment () может получить атрибут $env в коде разработки и выполнить некоторые операции. Вы можете увидеть исходный код environment (). Этот метод имеет две функции: считывание значения $env, если значение не передано, и определение того, совпадает ли значение с $env, если значение передано. Образец. Если для приложения нет определения атрибута члена $env, это связано с тем, что PHP может добавить атрибуты позже, такие как:

class ClassField
{
    
}

$class_field = new ClassField();
$class_field->name = 'Laravel';
echo $class_field->name . PHP_EOL;

/* output:
Laravel

3. Конфигурация журнала

Laravel в основном использует библиотеку журналов Monolog для обработки журналов. Программа записи журналов Illuminate эквивалентна мосту Монолога, который соединяет библиотеку монолога с Laravel. Посмотрите на исходный код ConfigureLogging:: bootstrap ():

public function bootstrap(Application $app)
    {
        // Registration'log'service
        $log = $this->registerLogger($app);

        // Check if Monolog has been registered
        // It is assumed that there is no registration at first.
        if ($app->hasMonologConfigurator()) {
            call_user_func(
                $app->getMonologConfigurator(), $log->getMonolog()
            );
        } else {
            // 
            $this->configureHandlers($app, $log);
        }
    }
    
    protected function registerLogger(Application $app)
    {
        // Binding the'log'service to the container, the Writer object
        $app->instance('log', $log = new Writer(
            new Monolog($app->environment()), $app['events'])
        );

        return $log;
    }

В модуль журнала Laravel было встроено несколько типов обработчика журналов: Одиночный, Ежедневный, Системный журнал, Журнал ошибок. Выберите один из обработчиков в соответствии с конфигурацией “войти” в config/app.php файл. Посмотрите на исходный код конфигурационных обработчиков ():

    protected function configureHandlers(Application $app, Writer $log)
    {
        $method = 'configure'.ucfirst($app['config']['app.log']).'Handler';

        $this->{$method}($app, $log);
    }

Метод configureHandlers () также является трюком. Найдите имя метода и вызовите его. Это часто используется в Laravel. Например, модуль файловой системы имеет исходный код типа “создать”. ucfirst (xxxx).”Драйвер”, который является хорошим дизайном. Здесь мы рассмотрим исходный код для configure Daily Handler (), а остальные три аналогичны:

protected function configureDailyHandler(Application $app, Writer $log)
    {
        // Resolution of'config'service
        $config = $app->make('config');
        // The default setting is null.
        $maxFiles = $config->get('app.log_max_files');

        $log->useDailyFiles(
            $app->storagePath().'/logs/laravel.log', // storage/log/laravel.log
            is_null($maxFiles) ? 5 : $maxFiles, // 5
            $config->get('app.log_level', 'debug') 
        );
    }
    
    // Writer.php
    public function useDailyFiles($path, $days = 0, $level = 'debug')
    {
        $this->monolog->pushHandler(
            $handler = new RotatingFileHandler($path, $days, $this->parseLevel($level))
        );

        $handler->setFormatter($this->getDefaultFormatter());
    }

Значения журнала печатаются в laravel. регистрируйте с помощью функции RotatingFileHandler () монолога. Конечно, в прикладных программах значения переменных часто печатаются в Log:: info (), Log:: warning (), Log:: debug (), который является методом, определенным в классе Writer. Фасад бревна Освещает Опорные фасады Бревна:

class Log extends Facade
{
    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor()
    {
        return 'log';
    }
}

Служба ‘ log ‘ зарегистрирована на первом шаге исходного кода bootstrap () выше. Конечно, я говорил об использовании фасада для получения услуг из контейнеров. Это не сложно. Посмотрите на исходный код resolveFacadeInstance () для подсветки фасадов поддержки фасада.

protected static function resolveFacadeInstance($name)
    {
        if (is_object($name)) {
            return $name;
        }

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

        Return static:: $resolvedInstance [$name] = static:$app [$name]; //In fact, it's using $app ['log'] to get services.
    }

4. обработка исключений

Обработка исключений очень важна. В обработчике исключений класса обработки исключений приложения Laravel есть метод report (), который можно использовать для отправки стеков исключений программ сторонним службам, таким как Sentry (позже поговорим об этом Sentry, артефакт эффективности), например, об исключении в среде производственного кода онлайн, и ясно, что этот метод можно использовать для отправки стеков исключений программ сторонним службам, таким как Sentry (позже поговорим об этом Sentry, артефакт эффективности). Вся стопка, какая строка неверна?

Хорошо, посмотрите исходный код запуска для настроек исключений, исходный код для обработки исключений:: bootstrap ():

public function bootstrap(Application $app)
    {
        $this->app = $app;

        error_reporting(-1);
        // Error, throw new ErrorException
        set_error_handler([$this, 'handleError']);
        // Handling exceptions, using report () method to report, can integrate third-party service Sentry as ExceptionReportHandler for exception reporting
        set_exception_handler([$this, 'handleException']);

        register_shutdown_function([$this, 'handleShutdown']);

        if (! $app->environment('testing')) {
            ini_set('display_errors', 'Off');
        }
    }

Здесь мы сосредоточимся на исходном коде HandleException ():

public function handleException($e)
    {
        if (! $e instanceof Exception) {
            $e = new FatalThrowableError($e);
        }
        // (new App\Exceptions\Handler($container))->report($e)
        $this->getExceptionHandler()->report($e);

        if ($this->app->runningInConsole()) {
            $this->renderForConsole($e);
        } else {
            $this->renderHttpResponse($e);
        }
    }
    
    protected function getExceptionHandler()
    {
        // Resolve the App Exceptions Handler object
        // singleton () binding has been done in boostrap / app. PHP
        return $this->app->make('Illuminate\Contracts\Debug\ExceptionHandler');
    }
    
    protected function renderHttpResponse(Exception $e)
    {
        // Use (new App Exceptions Handler ($container) - > render (Request $request, $e)
        $this->getExceptionHandler()->render($this->app['request'], $e)->send();
    }

Как вы знаете из исходного кода, основное внимание уделяется сообщению об исключениях с использованием метода report () Обработчика исключений приложений, такого как отчеты о стеках исключений и другая полезная информация для Sentry; метод render () Обработчика исключений приложений отправляется браузеру через запрос. Об использовании стороннего сервиса Sentry для создания отчетов об аномалиях после подробного обсуждения наша компания использует такие артефакты эффективности каждый день, очень полезные, достойные рекомендации.

5. Зарегистрируйте Фасады

Route:: get () часто используется в файлах маршрутизации, но классов маршрутов не существует. Маршрут-это просто псевдоним для класса внешнего вида класса поддержки Illuminate. Маршрут:: Этот псевдоним используется для упрощения использования PHP встроенной функции class_alias (строка, $класс, $строка, $псевдоним) для классификации класса. Имя. Посмотрите исходный код для фасадов регистров:: bootstrap ():

    public function bootstrap(Application $app)
    {
        Facade::clearResolvedInstances();

        Facade::setFacadeApplication($app);

        AliasLoader::getInstance($app->make('config')->get('app.aliases', []))->register();
    }
    
    // \Illuminate\Support\Facades\Facade
    public static function clearResolvedInstances()
    {
        static::$resolvedInstance = [];
    }
    
    // \Illuminate\Support\Facades\Facade
    public static function setFacadeApplication($app)
    {
        static::$app = $app;
    }

$$app->make ("конфигурация")->get ("псевдонимы приложений", []) Считайте значение “псевдонимов” из config/app.php, а затем зарегистрируйте псевдонимы класса внешнего вида. Зарегистрированными классами внешнего вида являются:

    'aliases' => [

        'App' => Illuminate\Support\Facades\App::class,
        'Artisan' => Illuminate\Support\Facades\Artisan::class,
        'Auth' => Illuminate\Support\Facades\Auth::class,
        'Blade' => Illuminate\Support\Facades\Blade::class,
        'Cache' => Illuminate\Support\Facades\Cache::class,
        'Config' => Illuminate\Support\Facades\Config::class,
        'Cookie' => Illuminate\Support\Facades\Cookie::class,
        'Crypt' => Illuminate\Support\Facades\Crypt::class,
        'DB' => Illuminate\Support\Facades\DB::class,
        'Eloquent' => Illuminate\Database\Eloquent\Model::class,
        'Event' => Illuminate\Support\Facades\Event::class,
        'File' => Illuminate\Support\Facades\File::class,
        'Gate' => Illuminate\Support\Facades\Gate::class,
        'Hash' => Illuminate\Support\Facades\Hash::class,
        'Lang' => Illuminate\Support\Facades\Lang::class,
        'Log' => Illuminate\Support\Facades\Log::class,
        'Mail' => Illuminate\Support\Facades\Mail::class,
        'Notification' => Illuminate\Support\Facades\Notification::class,
        'Password' => Illuminate\Support\Facades\Password::class,
        'Queue' => Illuminate\Support\Facades\Queue::class,
        'Redirect' => Illuminate\Support\Facades\Redirect::class,
        'Redis' => Illuminate\Support\Facades\Redis::class,
        'Request' => Illuminate\Support\Facades\Request::class,
        'Response' => Illuminate\Support\Facades\Response::class,
        'Route' => Illuminate\Support\Facades\Route::class,
        'Schema' => Illuminate\Support\Facades\Schema::class,
        'Session' => Illuminate\Support\Facades\Session::class,
        'Storage' => Illuminate\Support\Facades\Storage::class,
        'URL' => Illuminate\Support\Facades\URL::class,
        'Validator' => Illuminate\Support\Facades\Validator::class,
        'View' => Illuminate\Support\Facades\View::class,

    ],

Знать из приведенного выше массива псевдонимов Маршрут пока Осветить фасады поддержки Маршрут::класс Псевдоним, так что Route::get() На самом деле это так. Осветите маршрут поддержки::get() Посмотрите исходный код методов getInstance () и register () класса AliasLoader:

public static function getInstance(array $aliases = [])
    {
        if (is_null(static::$instance)) {
            // Here, $aliases is the $aliases [], which is the value of'aliases'in config/app.php.
            return static::$instance = new static($aliases);
        }

        $aliases = array_merge(static::$instance->getAliases(), $aliases);

        static::$instance->setAliases($aliases);

        return static::$instance;
    }
    
    public function register()
    {
        if (! $this->registered) {
            $this->prependToLoaderStack();

            $this->registered = true;
        }
    }
    
    protected function prependToLoaderStack()
    {
        // Place Alias Loader:: load () on the stack of auto-loading functions, where the stack head is located.
        spl_autoload_register([$this, 'load'], true, true);
    }

И исходный код функции loader ():

    public function load($alias)
    {
        if (isset($this->aliases[$alias])) {
            // @link http://php.net/manual/en/function.class-alias.php
            return class_alias($this->aliases[$alias], $alias);
        }
    }

Это делается для установки псевдонима для класса внешнего вида с помощью class_alias(). поэтому Route::get() Процесс вызова заключается, прежде всего, в том, чтобы найти класс Route , пройти через стек функций автоматической загрузки Загрузчик псевдонимов::load() Поиск функции Маршрут да Освещает маршрут Псевдоним, затем позвоните IlluminateSupportFacadesRoute::get() Конечно, здесь IlluminateSupportFacadesRoute Нет get() Статический метод, затем вызовите родительский класс Фасад Из __callStatic() Чтобы найти имя маршрутизатор Услуга под названием “маршрут” – это услуга, которая была зарегистрирована в контейнерах в течение длительного времени. Осветите маршрутизатор маршрутизации Объект, чтобы в конечном итоге вызвать Осветите маршрутизатор маршрутизации::get() Метод. Этот процесс в основном использует два метода: один-псевдоним класса внешнего вида; другой-перегрузка PHP, которую можно увидеть в этой статье: перегрузка PHP в учебных заметках Laravel.

6. Зарегистрируйте Поставщиков

Регистрация внешнего вида зарегистрирована в config/app.php $псевдонимы[ ] Регистрация поставщиков-это регистрация. $провайдеры[ ] Значение. Посмотрите исходный код для поставщиков регистра:: bootstrap ():

public function bootstrap(Application $app)
    {
        $app->registerConfiguredProviders();
    }
    
    // Application.php
    public function registerConfiguredProviders()
    {
        // Find out if bootstrap/cache/services.php has this cache file
        // Services.php is a cached file that stores the array values of service providers:
        // return [
        //    'providers' => [],
        //    'eager'     => [],
        //    'deferred'  => [],
        //    'when'      => []
        // ];
        $manifestPath = $this->getCachedServicesPath();
        
        // Load the'$providers []'array value in config/app.php through the load () method
        (new ProviderRepository($this, new Filesystem, $manifestPath))
                    ->load($this->config['app.providers']);
    }

Посмотрите на исходный код для load ():

public function load(array $providers)
    {
        // Check whether bootstrap / cache / services. PHP has this cache file
        // Not at the first startup.
        $manifest = $this->loadManifest();
        // If you don't have this cached file at first, put the value in $providers []
        if ($this->shouldRecompile($manifest, $providers)) {
            // Then compile the services. PHP cache file based on $providers []
            $manifest = $this->compileManifest($providers);
        }

        foreach ($manifest['when'] as $provider => $events) {
            // Register service providers with event monitoring
            // service providers that contain event listeners all have when () functions returned
            $this->registerLoadEvents($provider, $events);
        }

        foreach ($manifest['eager'] as $provider) {
            // Register the service provider in the'eager'field into the container.
            // that is, traverse each service provider and call the register () method in it
            // Register specific services in containers
            $this->app->register($this->createProvider($provider));
        }

        // Register service providers with delays,
        // deferred's service provider is to set $defer = true and to provide a provide () method to return the name of the service bound to the container
        $this->app->addDeferredServices($manifest['deferred']);
    }

Посмотрите на исходный код для компиляции метода манифеста компиляции кэшированного файла ():

protected function compileManifest($providers)
    {
        $manifest = $this->freshManifest($providers);

        foreach ($providers as $provider) {
            $instance = $this->createProvider($provider);
            // Depending on the defer attribute of each service provider, see if it is a service provider with delayed loading
            if ($instance->isDeferred()) {
                //For delayed loading, write it into the 'deferred' field according to the service name provided by the provides () method.
                // So service providers with delayed loading provide () methods
                foreach ($instance->provides() as $service) {
                    $manifest['deferred'][$service] = $provider;
                }
                // Register the service provider with events using the value provided by the when () function.
                $manifest['when'][$provider] = $instance->when();
            } else {
                // instead of delayed loading, put it in the'eager'field and register the service provider with $this - > app - > register ().
                $manifest['eager'][] = $provider;
            }
        }
        // Finally, it is written to the services.php cache file
        return $this->writeManifest($manifest);
    }
    
    protected function freshManifest(array $providers)
    {
        return ['providers' => $providers, 'eager' => [], 'deferred' => []];
    }

Подводя итог, регистрация поставщиков заключается в том, чтобы запустить всех поставщиков услуг, определенных $providers [] в config/app.php, службы, которые не связаны с поставщиками услуг отсрочки, и поставщики услуг отсрочки ждут, пока связанные с ними службы не понадобятся для выполнения привязки.

7. Запустите Провайдеров

Последний шаг-запустить программу. Посмотрите на поставщиков загрузки:: исходный код bootstrap ():

public function bootstrap(Application $app)
    {
        $app->boot();
    }
    
    public function boot()
    {
        // If the program has started, it returns, apparently not yet started, still in booting state.
        if ($this->booted) {
            return;
        }
        // Callbacks registered at $bootingCallbacks [] before application instantiation
        $this->fireAppCallbacks($this->bootingCallbacks);
        // Previously, all service providers using the Application:: register () method were written to $service providers []
        // Here the boot () method in each service provider is executed in turn, if it exists.
        array_walk($this->serviceProviders, function ($p) {
            $this->bootProvider($p);
        });

        $this->booted = true;
        // Callbacks registered at $bootedCallbacks [] before application instantiation
        $this->fireAppCallbacks($this->bootedCallbacks);
    }
    
    protected function bootProvider(ServiceProvider $provider)
    {
        if (method_exists($provider, 'boot')) {
            return $this->call([$provider, 'boot']);
        }
    }

Как вы можете видеть из приведенного выше исходного кода, шаги (7) и (6) аналогичны: шаг (6) заключается в выполнении метода register () каждого поставщика услуг, который по очереди не откладывается; шаг (7) заключается в выполнении метода boot () каждого поставщика услуг, который по очереди не откладывается, если он существует. Итак, в разделе поставщика услуг на официальном сайте говорится о способе загрузки:

Этот метод вызывается после регистрации всех других поставщиков услуг, что означает, что у вас есть доступ ко всем другим услугам, зарегистрированным платформой

Здесь мы можем понять, почему это предложение означает.

Прежде чем я рассказал о методе Application:: register (), был код, который проверял, запущена ли программа.

public function register($provider, $options = [], $force = false)
    {
        ...
        
        if ($this->booted) {
            $this->bootProvider($provider);
        }

        return $provider;
    }

Приложение не было запущено при первом создании экземпляра. После выполнения всех методов загрузки поставщика услуг БЕЗ ОТСРОЧКИ () программа запустилась: $this->загружено;

Хорошо, подготовка к запуску программы завершена. Процесс не является сложным. Его нужно только разобрать шаг за шагом, чтобы в основном понять, какую конкретную работу выполнял Laravel, когда он начинался.

Резюме: В этой статье в основном изучались семь этапов подготовки к запуску Laravel: 1. Обнаружение среды обнаружения; 2. Конфигурация загрузки конфигурации; 3. Ведение журнала конфигурации; 4. Обработка исключений; 5. Регистрация фасадов Регистрация фасадов; 6. Регистрация поставщиков Поставщиков; 7. Запуск поставщиков и поставщиков. В следующий раз, когда у вас будет хорошая технология, которой вы можете поделиться, увидимся тогда.

Добро пожаловать в Laravel-Китай.

RightCapital набирает сотрудников Laravel DevOps