在前面一篇《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在哪些方面轻了。
- 关于.ENV文件和config配置文件的加载,但实际上更建议将Lumen的与Laravel的保持一致
- 在new App实例的时候,Lumen所做的初始化工作,比Laravel少了一些,例如,包自动发现,路径的注册,基本服务提供者和一些aliases等。
- 关于request需要通过默认中间件。但其实我觉得有些还是必要的,比如AppHttpMiddlewareCheckForMaintenanceMode::class, 和IlluminateFoundationHttpMiddlewareValidatePostSize::class, 等。
- 我个人认为应该是相比与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包。