• Laravel源码解析--看看Lumen到底比Laravel轻在哪里


    在前面一篇《Laravel源码解析--Laravel生命周期详解》中我们利用xdebug详细了解了下Laravel一次请求中到底做了哪些处理。今天我们跟 Lumen 对比下,看看 Lumen 比 Laravel 轻在哪里?

    1、Lumen生命周期

    相比于Laravel,在Lumen中,你对框架有着更多的控制权。Lumen的入口文件相比于Laravel要简单许多。

    <?php
    
    /*
    |--------------------------------------------------------------------------
    | Create The Application
    |--------------------------------------------------------------------------
    |
    | First we need to get an application instance. This creates an instance
    | of the application / container and bootstraps the application so it
    | is ready to receive HTTP / Console requests from the environment.
    |
    */
    
    $app = require __DIR__.'/../bootstrap/app.php';
    
    /*
    |--------------------------------------------------------------------------
    | Run The Application
    |--------------------------------------------------------------------------
    |
    | Once we have the application, we can handle the incoming request
    | through the kernel, and send the associated response back to
    | the client's browser allowing them to enjoy the creative
    | and wonderful application we have prepared for them.
    |
    */
    
    $app->run();

    同样的,我们先看下 bootstrap/app.php 文件。

    // 1、毫无疑问,首先加载自动加载
    require_once __DIR__.'/../vendor/autoload.php';
    
    // 2、将根目录下的.env文件中的配置加载到$_ENV、$_SERVER和putfile()中,对Laravel生命周期有印象的应该还记得
    // Laravel中是在$bootstrappers数组中,先加载.ENV文件,然后再加载config/*.php里的所有配置文件。
    // 而在Lumen中,默认只加载了.ENV中的文件,你可以将所有的配置信息都写在.ENV文件中,然后在项目中可以用env()方法获取。
    // 当然,你也可以像Laravel那样,将所有的配置信息放到config/*.php下面,不过这需要你在获取$app实例后手动调用$app->configure('api');方法。
    // 这里就是Lumen比Laravel轻的一个地方,但我感觉只使用.ENV文件或config配置都不太合理,还是两个配合使用最为方便。所以这里Lumen就不会比Laravel轻了。
    try {
        (new DotenvDotenv(dirname(__DIR__)))->load();
    } catch (DotenvExceptionInvalidPathException $e) {
        //
    }
    
    /*
    |--------------------------------------------------------------------------
    | Create The Application
    |--------------------------------------------------------------------------
    |
    | Here we will load the environment and create the application instance
    | that serves as the central piece of this framework. We'll use this
    | application as an "IoC" container and router for this framework.
    |
    */
    // 3、创建Lumen App实例
    $app = new LaravelLumenApplication(
        dirname(__DIR__)
    );

    创建Lumen实例的时候,肯定也做了一些初始化工作。

    /**
         * Create a new Lumen application instance.
         *
         * @param  string|null  $basePath
         * @return void
         */
        public function __construct($basePath = null)
        {
         // 设置时区
    if (! empty(env('APP_TIMEZONE'))) { date_default_timezone_set(env('APP_TIMEZONE', 'UTC')); }      // 设置路径 $this->basePath = $basePath;
        // 向容器中的instances中绑定app,path,env,config等,并绑定一些aliases
    $this->bootstrapContainer();
         // 注册错误处理
    $this->registerErrorHandling();
         // 向容器中注入Router
    $this->bootstrapRouter(); }

    相比Laravel,Lumen做的初始化工作要少很多--包自动发现、路径的注册、一些基础服务提供者的注册、注册aliases时也少了很多。得到App实例后,让我们继续回头看 bootstraps/app.php 中去。

    // 3、创建Lumen App实例
    $app = new LaravelLumenApplication(
        dirname(__DIR__)
    );
    
    // 4、如果你需要在应用中使用门面方法,则取消此行注释
    // $app->withFacades();
    
    // 5、如果你想要在应用中使用Eloquent,则取消此行注释
    // $app->withEloquent();
    
    /*
    |--------------------------------------------------------------------------
    | Register Container Bindings
    |--------------------------------------------------------------------------
    |
    | Now we will register a few bindings in the service container. We will
    | register the exception handler and the console kernel. You may add
    | your own bindings here if you like or you can make another file.
    |
    */
    // 6、注册容器绑定,绑定异常处理类的实现和Console的实现。
    // 相比Laravel,Lumen少绑定了一个HttpKernel的实现
    $app->singleton(
        IlluminateContractsDebugExceptionHandler::class,
        AppExceptionsHandler::class
    );
    
    $app->singleton(
        IlluminateContractsConsoleKernel::class,
        AppConsoleKernel::class
    );
    
    /*
    |--------------------------------------------------------------------------
    | Register Middleware
    |--------------------------------------------------------------------------
    |
    | Next, we will register the middleware with the application. These can
    | be global middleware that run before and after each request into a
    | route or middleware that'll be assigned to some specific routes.
    |
    */
    
    // 7、每个request都需要通过的一个中间件组,相比Laravel,少了一些固定要走的中间件,那么如果你把Laravel中固定的中间件注释掉,是不是就一样了呢?
    // $app->middleware([
    //     AppHttpMiddlewareExampleMiddleware::class
    // ]);
    
    // 8、注册路由中间件,同样在Laravel中,也默认定义了很多路由中间件
    // $app->routeMiddleware([
    //     'auth' => AppHttpMiddlewareAuthenticate::class,
    // ]);
    
    /*
    |--------------------------------------------------------------------------
    | Register Service Providers
    |--------------------------------------------------------------------------
    |
    | Here we will register all of the application's service providers which
    | are used to bind services into the container. Service providers are
    | totally optional, so you are not required to uncomment this line.
    |
    */
    
    // 9、按需注册服务提供者,而在Laravel中,除了注册了几个基础的服务提供在,还会注册config/app.php中providers数组里所有的服务提供者。
    // 还是那句话,如果你把config/app.php中providers数组中都注释掉呢?对了,在Laravel5.5引入包自动发现后,它还会注册bootstrap/cache/packages.php中的服务提供者
     $app->register(AppProvidersAppServiceProvider::class);
     $app->register(AppProvidersAuthServiceProvider::class);
     $app->register(AppProvidersEventServiceProvider::class);
    
    /*
    |--------------------------------------------------------------------------
    | Load The Application Routes
    |--------------------------------------------------------------------------
    |
    | Next we will include the routes file so that they can all be added to
    | the application. This will provide all of the URLs the application
    | can respond to, as well as the controllers that may handle them.
    |
    */
    // 10、注册路由
    $app->router->group([
        'namespace' => 'AppHttpControllers',
    ], function ($router) {
        require __DIR__.'/../routes/web.php';
    });
    
    // 11、返回App实例
    return $app;

    到这里,整个Lumen应用已经初始化完毕。之后 $app->run(); 其实就是根据之前注册的路由(执行每个服务提供者的boot()方法,也在这个方法中),然后进行路由分发。这与Laravel并没有什么太大区别。

    综上所述,我们总结一下Lumen应用比Laravel在哪些方面轻了。

    1. 关于.ENV文件和config配置文件的加载,但实际上更建议将Lumen的与Laravel的保持一致
    2. 在new App实例的时候,Lumen所做的初始化工作,比Laravel少了一些,例如,包自动发现,路径的注册,基本服务提供者和一些aliases等。
    3. 关于request需要通过默认中间件。但其实我觉得有些还是必要的,比如AppHttpMiddlewareCheckForMaintenanceMode::class, 和IlluminateFoundationHttpMiddlewareValidatePostSize::class, 等。
    4. 我个人认为应该是相比与Laravel,耗时最多的一个,就是对各种服务提供者的注册和引导(执行boot()方法)。

    下面做个测试,当不对Laravel做任何处理的时候,看看启动需要多久?

    Route::get('/', function () {
        $end = microtime(true);
        return $end - LARAVEL_START;
    //    return view('welcome');
    });

    差不多是在 0.16353797912598 秒左右。而Lumen在开启一些基本的服务后的启动时间为 0.043106079101562 ,与Laravel相差了将近有4倍。相当于光启动框架,任何逻辑处理都还没开始,Laravel比Lumen多耗时0.12s。如果我们利用一些Laravel的性能优化策略,比如缓存配置文件等会稍稍减少Laravel的启动时间 0.12118005752563 。因为php的特性,每一个request,都需要将之前的所有动作执行一遍,所以App的启动还是一个比较耗时的任务。

    这时候我就想安利一下颠覆php的拓展--swoole。下一章会讲解给Laravel插上翅膀的一个用swoole做的composer包。

  • 相关阅读:
    weiPHP微信开发框架
    win7系统
    csdn博客频道
    一步一步安装Git控件版本工具
    php源码,php网站源码,php源码下载
    czz数据专家
    禁用了传说中的PHP危险函数之后,Laravel的定时任务不能执行了?
    php禁用函数设置及查看方法详解
    laravel项目thinksns-plus安装出现RuntimeException Symlink from * to * failed错误
    laravel框架使用中错误及解决办法总结
  • 原文地址:https://www.cnblogs.com/johnson108178/p/10069240.html
Copyright © 2020-2023  润新知