你知道Laravel的启动过程是怎样的吗?

178 阅读2分钟

laravel的启动过程,也是laravel的核心,对这个过程有一个了解,有助于得心应手的使用框架,希望能对大家有点帮助。

提示:在此之前,最好看一下官方文档,大概知道laravel,再来看这个笔记,这样效果可能会好一点。

统一入口
laravel框架使用了统一入口,入口文件:/public/index.php

<?php
//自动加载文件设置
require __DIR__.'/../bootstrap/autoload.php';

//初始化服务容器(可以查看一下关于‘服务容器’的相关文档)
$app = require_once __DIR__.'/../bootstrap/app.php';

//通过服务容器生成一个kernel类的实例(Illuminate\Contracts\Http\Kernel实际上只是一个接口,真正生成的实例是App\Http\Kernel类,至于怎么把接口和类关联起来,请查看Contracts相关文档)
$kernel = $app->make('Illuminate\Contracts\Http\Kernel');

//运行Kernel类的handle方法,主要动作是运行middleware和启动URL相关的Contrller
$response = $kernel->handle(
    $request = Illuminate\Http\Request::capture()
);

//控制器返回结果之后的操作,暂时还没看,以后补上
$response->send();

kernel->terminate(

kernel−>terminate(request, $response);

自动加载文件
laravel的自动加载,其实也就是Composer的自动加载

我的理解是,Composer根据声明的依赖关系,从相关库的源下载代码文件,并根据依赖关系在 Composer 目录下生成供类自动加载的 PHP 脚本,使用的时候,项目开始处引入 “/vendor/autoload.php” 文件,就可以直接实例化这些第三方类库中的类了。

那么,Composer 是如何实现类的自动加载的呢?接下来,我们从 laravel 的入口文件开始顺藤摸瓜往里跟进,来一睹 Composer 自动加载的奥妙。

代码:/bootstrap/autoload.php

<?php
define('LARAVEL_START', microtime(true));

//这就是传说中Composer的自动加载文件
require __DIR__.'/../vendor/autoload.php';

//Composer自动生成的各个核心类的集合,如果你需要修改一些vendor里面的文件来查看一些laravel运行细节,那么就请删除此文件
$compiledPath = __DIR__.'/../vendor/compiled.php';

if (file_exists($compiledPath))
{
    require $compiledPath;
}

代码: laravel/vendor/autoload.php

<?php

// autoload.php @generated by Composer

require_once __DIR__ . '/composer' . '/autoload_real.php';
//别被吓到了,他就是autoload_real.php文件的类名而已
return ComposerAutoloaderInit03dc6c3c47809c398817ca33ec5f6a01::getLoader();

代码:laravel/vendor/composer/autoload_real.php
主要是getLoader方法里面,加了注释的几行,这是关键

<?php

// autoload_real.php @generated by Composer

class ComposerAutoloaderInit03dc6c3c47809c398817ca33ec5f6a01
{
    private static $loader;

    public static function loadClassLoader($class)
    {
        if ('Composer\Autoload\ClassLoader' === $class) {
            require __DIR__ . '/ClassLoader.php';
        }
    }

    public static function getLoader()
    {
        if (null !== self::$loader) {
            return self::$loader;
        }

        spl_autoload_register(array('ComposerAutoloaderInit03dc6c3c47809c398817ca33ec5f6a01', 'loadClassLoader'), true, true);
        self::$loader = $loader = new \Composer\Autoload\ClassLoader();
        spl_autoload_unregister(array('ComposerAutoloaderInit03dc6c3c47809c398817ca33ec5f6a01', 'loadClassLoader'));

        $includePaths = require __DIR__ . '/include_paths.php';
        array_push($includePaths, get_include_path());
        set_include_path(join(PATH_SEPARATOR, $includePaths));

        //Psr0标准-设置命名空间对应的路径,以便于随后自动加载相关类文件(看看psr0和psr4的区别)
        $map = require __DIR__ . '/autoload_namespaces.php';
        foreach ($map as $namespace => $path) {
            $loader->set($namespace, $path);
        }
        //Psr4标准-设置命名空间对应的路径,以便于随后自动加载相关类文件(看看psr0和psr4的区别)
        $map = require __DIR__ . '/autoload_psr4.php';
        foreach ($map as $namespace => $path) {
            $loader->setPsr4($namespace, $path);
        }

        //设置类文件路径与类名的对应关系,以便于随后自动加载相关类文件(可能你有一部分类,由于历史原因,他们的命名空间不遵守PSR0和PSR4,你就可以使用此方法自动加载)
        $classMap = require __DIR__ . '/autoload_classmap.php';
        if ($classMap) {
            $loader->addClassMap($classMap);
        }

        //根据上述三种方法注册自动加载文档的方法,可以查看一下PHP的spl_autoload_register和__autoload方法
        $loader->register(true);

        //加载公用方法,比如app()方法取得一个application实例,就是这里加载的,可以查看一下autoload_files.php文件都加载了什么公用方法,有很多关于 array的操作方法哦
        $includeFiles = require __DIR__ . '/autoload_files.php';
        foreach ($includeFiles as $file) {
            composerRequire03dc6c3c47809c398817ca33ec5f6a01($file);
        }

        return $loader;
    }
}

function composerRequire03dc6c3c47809c398817ca33ec5f6a01($file)
{
    require $file;
}

对于laravel自动加载过程的总结

laravel自动加载的过程就是这样实现的,总结为四种加载方式:

PSR0加载方式—对应的文件就是autoload_namespaces.php
PSR4加载方式—对应的文件就是autoload_psr4.php
其他加载类的方式—对应的文件就是autoload_classmap.php
加载公用方法—对应的文件就是autoload_files.php

怎么样自定义自动加载方式

如果某些文件,需要自动自定义加载方式,可以在Composer.json文件中定义

"autoload" : {
    //以第一种方式自动加载,表示app目录下的所有类的命名空间都是以Apppsr0开始且遵循psr0规范(注意:您的laravel中没有此项,作为示意例子)
    "psr-0" : {
        "AppPsr0": "apppsr0/"
    },
    //以第二种方式自动加载,表示app目录下的所有类的命名空间都是以App开始且遵循psr4规范
    "psr-4" : {
        "App\\": "app/"
    },
    //以第三种加载方式自动加载,它会将所有.php和.inc文件中的类提出出来然后以类名作为key,类的路径作为值
    "classmap" : ["database"],
    //以第四种加载方式自动加载,composer会把这些文件都include进来(注意:您的laravel中没有此项,作为示意例子)
    "files" : ["common/util.php"]

}