插件窝 干货文章 Laravel生命周期启动(从创建应用实例到注册基础服务)过程解析

Laravel生命周期启动(从创建应用实例到注册基础服务)过程解析

class instance abstract gt 960    来源:    2024-10-29

引言

在了解了Laravle10大概的生命周期流程,从执行到回调整个步骤,接下来我们来对其中的流程进行详细剖解来看一下它究竟是怎样执行的。

在入口文件中有一个步骤是

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

这样的,它加载了bootstrap/app.php文件,那么这个文件究竟做了写什么?我们一起往下看!

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.
|我们要做的第一件事是创建一个新的Laravel应用程序实例,
|它作为Laravel所有组件的“粘合剂”,
|使系统绑定所有不同部分的IoC(控制反转)容器。
*/
$app = new Illuminate\Foundation\Application(
    $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);

意思就是说此处创建了应用实例,传入了项目的基础路径,那么这个Application类里面又是怎样的逻辑?让我们往下看

Application的构造方法: 在里面首先执行了setBasePath方法,在里面设置了一些基本路径

public function __construct($basePath = null)
    {
        if ($basePath) {
            $this->setBasePath($basePath);
        }
        $this->registerBaseBindings();
        $this->registerBaseServiceProviders();
        $this->registerCoreContainerAliases();
    }

setBasePath设置了语言包、配置文件、静态资源、view页面、引导框架目录、数据库配置、日志缓存等基本路径。

/**
         * Set the base path for the application.
         *
         * @param  string  $basePath
         * @return $this
         */
        public function setBasePath($basePath)
        {
            $this->basePath = rtrim($basePath, '\/');
            $this->bindPathsInContainer();
            return $this;
        }
    /**
     * Bind all of the application paths in the container.
     *
     * @return void
     */
    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());
    }

设置路径通过instance函数进行的,我们看一下instance函数。instance函数里面首先执行了removeAbstractAlias方法,对传入的变量进行清空,即(path.base、path、path.lang)等,如果这些变量都存在的话,就把它们释放删除了。

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;
}
/**
 * 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]);
            }
        }
    }
}

在instance第二行里面,调用了bound函数,去确定给定的抽象类型是否已绑定,是否已被实例化,是否是别名。

$isBound = $this->bound($abstract);
    /**
     * Determine if the given abstract type has been bound.
     *
     * @param  string  $abstract
     * @return bool
     */
    public function bound($abstract)
    {
        return isset($this->bindings[$abstract]) ||
               isset($this->instances[$abstract]) ||
               $this->isAlias($abstract);
    }

接着就是删除别名

//删除别名
unset($this->aliases[$abstract]);

把实例放到instances数组中

$this->instances[$abstract] = $instance;

最后根据第二行返回的$isBound的值去执行rebound函数,执行到这里时,项目所需要的instances实例就已经加载完毕了,基础路径已经全部加载完成了。

if ($isBound) {
            $this->rebound($abstract);
        }
    /**
     * Fire the "rebound" callbacks for the given abstract type.
     *
     * @param  string  $abstract
     * @return void
     */
    protected function rebound($abstract)
    {
        $instance = $this->make($abstract);
        foreach ($this->getReboundCallbacks($abstract) as $callback) {
            call_user_func($callback, $this, $instance);
        }
    }

接着又增加了三个实例到instances数组内

注册基础绑定

$this->registerBaseBindings();

把现有的实例注册为实例中的共享容器

/**
 * Register the basic bindings into the container.
 *
 * @return void
 */
protected function registerBaseBindings()
{
    static::setInstance($this);
    //1,调用静态方法setInstance设置实例
    $this->instance('app', $this);
    //2,调用Instance ,将现有的实例注册为实例中的共享容器,查看Instance这个方法        (代码instance,上面已经说过)
    //注册app,Container
    $this->instance(Container::class, $this);
    //3,在容器中注册mix获取版本化的mix文件路径
    $this->singleton(Mix::class);
    $this->singleton(PackageManifest::class, function () {
        return new PackageManifest(
            new Filesystem, $this->basePath(), $this->getCachedPackagesPath()
        );
    });
}

注册基础服务

$this->registerBaseServiceProviders();

查看registerBaseServiceProviders 注册所有基本服务提供商

/**
 * Register all of the base service providers.
 *
 * @return void
 */
protected function registerBaseServiceProviders()
{
    //注册事件服务
    $this->register(new EventServiceProvider($this));
    //注册日志
    $this->register(new LogServiceProvider($this));
    //注册路由
    $this->register(new RoutingServiceProvider($this));
}

注册容器别名

$this->registerCoreContainerAliases();

registerCoreContainerAliases 注册核心容器别名

将一些重要的接口绑定到容器中我们将能够在需要时解决它们

//http内核
$app->singleton(
    Illuminate\Contracts\Http\Kernel::class,
    App\Http\Kernel::class
);
//console内核
$app->singleton(
    Illuminate\Contracts\Console\Kernel::class,
    App\Console\Kernel::class
);
//laravel的异常处理
$app->singleton(
    Illuminate\Contracts\Debug\ExceptionHandler::class,
    App\Exceptions\Handler::class
);

到此app.php的内容已经解析完了。

以上就是Laravel生命周期启动(从创建应用实例到注册基础服务)过程解析的详细内容,更多关于Laravel生命周期的资料请关注插件窝其它相关文章!