概述
生命周期
index.php
1.1 检测是否处于维护模式
if (file_exists(__DIR__.'/../storage/framework/maintenance.php')) {
require __DIR__.'/../storage/framework/maintenance.php';
}
1.2 加载composer
自动加载文件
require __DIR__.'/../vendor/autoload.php';
1.3 加载初始化容器
$app = require_once __DIR__.'/../bootstrap/app.php';
1.3.1 初始化__construct()
class Application extends Container implements ApplicationContract, CachesConfiguration, CachesRoutes, HttpKernelInterface
{
public function __construct($basePath = null)
{
if ($basePath) {
$this->setBasePath($basePath);
}
$this->registerBaseBindings();
$this->registerBaseServiceProviders();
$this->registerCoreContainerAliases();
}
}
1.3.1.1 设置项目的根目录路径
public function setBasePath($basePath)
{
$this->basePath = rtrim($basePath, '/');
$this->bindPathsInContainer();
return $this;
}
protected function bindPathsInContainer()
{
//项目的app path
$this->instance('path', $this->path());
//根目录
$this->instance('path.base', $this->basePath());
//多语言翻译目录
$this->instance('path.lang', $this->langPath());
//config 配置文件路径
$this->instance('path.config', $this->configPath());
//public 目录路径
$this->instance('path.public', $this->publicPath());
//storage 目录路径
$this->instance('path.storage', $this->storagePath());
//数据库迁移文件路径
$this->instance('path.database', $this->databasePath());
//资源文件路径
$this->instance('path.resources', $this->resourcePath());
//bootstrap 文件路径
$this->instance('path.bootstrap', $this->bootstrapPath());
}
1.3.1.2 注册基本绑定到容器
protected function registerBaseBindings()
{
//把当前实例初始给类常量 $instance
static::setInstance($this);
//把当前实例注册到app这个字符串
$this->instance('app', $this);
//把当前实例注册到 Container
$this->instance(Container::class, $this);
//单利注册渲染前端打包渲染文件
$this->singleton(Mix::class);
//单利注册 composer 包相关的类到容器
$this->singleton(PackageManifest::class, function () {
return new PackageManifest(
new Filesystem, $this->basePath(), $this->getCachedPackagesPath()
);
});
}
1.3.1.3 注册基础服务
protected function registerBaseServiceProviders()
{
//注册事件监听
$this->register(new EventServiceProvider($this));
//注册日志服务
$this->register(new LogServiceProvider($this));
//注册路由服务
$this->register(new RoutingServiceProvider($this));
register();
// 判断 $this->getProvider($provider)当前容器中是否注册了这个服务,有直接返回
// 判断传递进来的第一个参数是否是一个字符串,如果是就new当前这个服务提供者
if (is_string($provider)) {
$provider = $this->resolveProvider($provider);
}
//调用当前传递进来的服务提供者的register()方法
$provider->register();
//判断当前服务提供者是否具有bindings属性,有就循环它,并且使用容器的bind方法绑定
if (property_exists($provider, 'bindings')) {
foreach ($provider->bindings as $key => $value) {
$this->bind($key, $value);
}
}
//判断当前服务提供者是否具有singletons属性,有就循环它,并且使用容器的singleton方法绑定
if (property_exists($provider, 'singletons')) {
foreach ($provider->singletons as $key => $value) {
$this->singleton($key, $value);
}
}
//将当前传递过来的服务提供者放入容器的$serviceProviders数组,并且使用$loadedProviders数组存储当前服务提供者的类名,并且标记(value)为true
$this->serviceProviders[] = $provider;
$this->loadedProviders[get_class($provider)] = true;
//判断当前的容器是否已经启动,如果启动了,就判断当前传递过来的服务提供者中是否具有boot方法,有就调用
if ($this->isBooted()) {
$this->bootProvider($provider);
}
$provider->callBootingCallbacks();
if (method_exists($provider, 'boot')) {
$this->call([$provider, 'boot']);
}
$provider->callBootedCallbacks();
//最后返回传递过来的服务提供者
}
1.3.1.4 给当前容器中的核心类绑定别名放入数组$aliases $abstractAliases
//别名当作数组的值,核心类当作当前数组的值
$this->aliases[$alias] = $abstract;
//核心类当作二维数组中的键,别名放入二维数组中
$this->abstractAliases[$abstract][] = $alias;
1.4 单利注册http内核
$app->singleton(
IlluminateContractsHttpKernel::class,
AppHttpKernel::class
);
1.5 单利注册命令行内核
$app->singleton(
IlluminateContractsConsoleKernel::class,
AppConsoleKernel::class
);
1.6 单利注册错误处理内核
$app->singleton(
IlluminateContractsDebugExceptionHandler::class,
AppExceptionsHandler::class
);
- 容器的单利注册方法
singleton()
实质是调用容器的bind()
方法,$this->bind($abstract, $concrete, true);
传递的第三个参数为true
即代表单利注册
第一步是先去容器数组中删除当前注册的服务unset($this->instances[$abstract], $this->aliases[$abstract]);
第二步判断,当前传递过来的参数二是否为null
也就代表在使用singleton()
方法的时候,可以只传递第一个参数,然后容器方法会做判断,如果没有传递第二个
参数,那么就会把第一个参数赋值给第二个参数
if (is_null($concrete)) {
$concrete = $abstract;
}
第三步判断当前传递的第二个需要绑定的类是否是一个匿名类,如果是匿名类就直接注册到数组$bindings
中$this->bindings[$abstract] = compact('concrete', 'shared');
如果不是一个匿名类,就进入判断中
if (! $concrete instanceof Closure) {
if (! is_string($concrete)) {
throw new TypeError(self::class.'::bind(): Argument #2 ($concrete) must be of type Closure|string|null');
}
$concrete = $this->getClosure($abstract, $concrete);
}
调用这个方法getClosure()
返回一个匿名类,绑定到数组中$bindings
第四步判断当前容器中是否已经绑定了这个抽象类,如果是,进入if
判断
$instance = $this->make($abstract);
foreach ($this->getReboundCallbacks($abstract) as $callback) {
call_user_func($callback, $this, $instance);
}
1.7 实例化IlluminateContractsHttpKernel
类,核心http请求内核,并调用
protected function syncMiddlewareToRouter()
{
//把当前的全局中间件赋值给路由的全局中间件组
//IlluminateCookieMiddlewareEncryptCookies::class, cookie加密
//IlluminateSessionMiddlewareStartSession::class, 开启session
//IlluminateViewMiddlewareShareErrorsFromSession::class,
//IlluminateContractsAuthMiddlewareAuthenticatesRequests::class,
//IlluminateRoutingMiddlewareThrottleRequests::class,
//IlluminateSessionMiddlewareAuthenticateSession::class,
//IlluminateRoutingMiddlewareSubstituteBindings::class,
//IlluminateAuthMiddlewareAuthorize::class,
$this->router->middlewarePriority = $this->middlewarePriority;
//把路由组
foreach ($this->middlewareGroups as $key => $middleware) {
//添加到路由类的数组$middlewareGroups中
$this->router->middlewareGroup($key, $middleware);
}
foreach ($this->routeMiddleware as $key => $middleware) {
//添加到路由类的数组$middleware
$this->router->aliasMiddleware($key, $middleware);
}
}
1.7.1 调用 handle()
第一步: $response = $this->sendRequestThroughRouter($request);
第二步: $this->bootstrap();
public function bootstrap()
{
if (! $this->app->hasBeenBootstrapped()) {
$this->app->bootstrapWith($this->bootstrappers());
}
}
第三步:
protected $bootstrappers = [
IlluminateFoundationBootstrapLoadEnvironmentVariables::class,
IlluminateFoundationBootstrapLoadConfiguration::class,
IlluminateFoundationBootstrapHandleExceptions::class,
IlluminateFoundationBootstrapRegisterFacades::class,
IlluminateFoundationBootstrapRegisterProviders::class,
IlluminateFoundationBootstrapBootProviders::class,
];
protected function bootstrappers()
{
return $this->bootstrappers;
}
第四步:
public function bootstrapWith(array $bootstrappers)
{
$this->hasBeenBootstrapped = true;
foreach ($bootstrappers as $bootstrapper) {
$this['events']->dispatch('bootstrapping: '.$bootstrapper, [$this]);
$this->make($bootstrapper)->bootstrap($this);
$this['events']->dispatch('bootstrapped: '.$bootstrapper, [$this]);
}
}
第五步:实例化数组$bootstrappers
中的类,并调用各自的bootstrap()
方法
//LoadEnvironmentVariables
public function bootstrap(Application $app)
{
if ($app->configurationIsCached()) {
return;
}
$this->checkForSpecificEnvironmentFile($app);
try {
$this->createDotenv($app)->safeLoad();
} catch (InvalidFileException $e) {
$this->writeErrorAndDie($e);
}
}
//LoadConfiguration 加载config 文件的配置
public function bootstrap(Application $app)
{
$items = [];
// First we will see if we have a cache configuration file. If we do, we'll load
// the configuration items from that file so that it is very quick. Otherwise
// we will need to spin through every configuration file and load them all.
if (is_file($cached = $app->getCachedConfigPath())) {
$items = require $cached;
$loadedFromCache = true;
}
// Next we will spin through all of the configuration files in the configuration
// directory and load each one into the repository. This will make all of the
// options available to the developer for use in various parts of this app.
$app->instance('config', $config = new Repository($items));
if (! isset($loadedFromCache)) {
$this->loadConfigurationFiles($app, $config);
}
// Finally, we will set the application's environment based on the configuration
// values that were loaded. We will pass a callback which will be used to get
// the environment in a web context where an "--env" switch is not present.
$app->detectEnvironment(function () use ($config) {
return $config->get('app.env', 'production');
});
date_default_timezone_set($config->get('app.timezone', 'UTC'));
mb_internal_encoding('UTF-8');
}
//HandleExceptions 注册异常处理类
public function bootstrap(Application $app)
{
self::$reservedMemory = str_repeat('x', 10240);
$this->app = $app;
error_reporting(-1);
set_error_handler([$this, 'handleError']);
set_exception_handler([$this, 'handleException']);
register_shutdown_function([$this, 'handleShutdown']);
if (! $app->environment('testing')) {
ini_set('display_errors', 'Off');
}
}
//RegisterFacades 注册门脸类 config.app.aliases类实现访问自动加载
public function bootstrap(Application $app)
{
Facade::clearResolvedInstances();
Facade::setFacadeApplication($app);
AliasLoader::getInstance(array_merge(
$app->make('config')->get('app.aliases', []),
$app->make(PackageManifest::class)->aliases()
))->register();
}
//RegisterProviders 实例化config.app.providers数组中的类
public function bootstrap(Application $app)
{
$app->registerConfiguredProviders();
}
//BootProviders 运行所有已注册到容器中类的boot方法
public function bootstrap(Application $app)
{
$app->boot();
}
第六步:实例化一个管道类 Pipline()
传递当前的容器给__construct()
方法,赋值给管道类的$this->container
变量
调用管道类的send()
方法并把当前的请求$request
当作参数传递进来,赋值给管道类的$this->passable
变量
链式调用管道类的through()
方法
(new Pipeline($this->app))
->send($request)
->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
->then($this->dispatchToRouter());
- 最重要之
dispatchToRouter()
方法,再次调用IlluminateRoutingRouter
类的dispatch()
方法
protected function dispatchToRouter()
{
return function ($request) {
$this->app->instance('request', $request);
return $this->router->dispatch($request);
};
}
调用方法dispatch($request)()
,把当前的request类赋值给$currentRequest
变量,接着调用dispatchToRoute()
方法
public function dispatch(Request $request)
{
$this->currentRequest = $request;
return $this->dispatchToRoute($request);
}
方法dispatchToRoute()
,调用findRoute()
方法,request
请求类当作参数
public function dispatchToRoute(Request $request)
{
return $this->runRoute($request, $this->findRoute($request));
}
方法 findRoute($request)
,调用match()
方法,$request
请求类当作参数
protected function findRoute($request)
{
$this->current = $route = $this->routes->match($request);
$this->container->instance(Route::class, $route);
return $route;
}
方法 match($request)
,首先得到当前的请求方法,get post head ...
在IlluminateRoutingRouteCollection
路由集合方法中,再次调用
get()
方法,拿到当前get
或者post
等等提交的所有路由信息,是一个请求方法为键的数组集合
public function match(Request $request)
{
$routes = $this->get($request->getMethod());
// First, we will see if we can find a matching route for this current request
// method. If we can, great, we can just return it so that it can be called
// by the consumer. Otherwise we will check for routes with another verb.
$route = $this->matchAgainstRoutes($routes, $request);
return $this->handleMatchedRoute($request, $route);
}
再次调用matchAgainstRoutes()
方法,第一个参数就是当前请求方法的数组,第二个参数就是请求类,匹配得到当前的路由类
protected function matchAgainstRoutes(array $routes, $request, $includingMethod = true)
{
[$fallbacks, $routes] = collect($routes)->partition(function ($route) {
return $route->isFallback;
});
return $routes->merge($fallbacks)->first(function (Route $route) use ($request, $includingMethod) {
return $route->matches($request, $includingMethod);
});
}
调用handleMatchedRoute()
方法
protected function handleMatchedRoute(Request $request, $route)
{
if (! is_null($route)) {
return $route->bind($request);
}
// If no route was found we will now check if a matching route is specified by
// another HTTP verb. If it is we will need to throw a MethodNotAllowed and
// inform the user agent of which HTTP verb it should use for this route.
$others = $this->checkForAlternateVerbs($request);
if (count($others) > 0) {
return $this->getRouteForMethods($request, $others);
}
throw new NotFoundHttpException;
}
最后
以上就是妩媚煎蛋为你收集整理的Laravel生命周期学习一的全部内容,希望文章能够帮你解决Laravel生命周期学习一所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复