Le framework est un très excellent Laravel
Cet article est. pour vous aider à bien comprendre les principes de fonctionnement du framework, afin que vous puissiez Au cours du processus d'entretien, il y a eu des discussions (vantage) L'apprentissage et la recherche du code source d'excellents frameworks aideront également à améliorer notre propre technologie. ceintures de sécurité, les conducteurs expérimentés sont sur le point de commencer à conduire ! ! ! PHP
Fichier d'entrée du frameworkLaravel
index.php
autoload.php
基本绑定($this、容器类Container等等)、 基本服务提供者的注册(Event、log、routing)、 核心类别名的注册(比如db、auth、config、router等)3. Commencez à traiter la
requête Http
make 方法从容器中解析指定的值为实际的类,比如 $app->make(Illuminate\Contracts\Http\Kernel::class); 解析出来 App\Http\Kernel handle 方法对 http 请求进行处理 实际上是 handle 中 sendRequestThroughRouter 处理 http 的请求 首先,将 request 绑定到共享实例 然后执行 bootstarp 方法,运行给定的引导类数组 $bootstrappers,这里是重点,包括了加载配置文件、环境变量、服务提供者、门面、异常处理、引导提供者等 之后,进入管道模式,经过中间件的处理过滤后,再进行用户请求的分发 在请求分发时,首先,查找与给定请求匹配的路由,然后执行 runRoute 方法,实际处理请求的时候 runRoute 中的 runRouteWithinStack 最后,经过 runRouteWithinStack 中的 run 方法,将请求分配到实际的控制器中,执行闭包或者方法,并得到响应结果4. Traiter le résultat Retour
require __DIR__.'/../vendor/autoload.php';
2. . Créez une instance de conteneur d'application
(cette instance hérite de la classe conteneur) et lie le noyau (web, ligne de commande, exception) pour faciliter leur analyse en cas de besoin Application
$app = require_once __DIR__.'/../bootstrap/app.php';
Container
. Le fichier est le suivant : <?php // 创建Laravel实例 【3】 $app = new Illuminate\Foundation\Application( $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__) ); // 绑定Web端kernel $app->singleton( Illuminate\Contracts\Http\Kernel::class, App\Http\Kernel::class); // 绑定命令行kernel $app->singleton( Illuminate\Contracts\Console\Kernel::class, App\Console\Kernel::class); // 绑定异常处理 $app->singleton( Illuminate\Contracts\Debug\ExceptionHandler::class, App\Exceptions\Handler::class); // 返回应用实例 return $app;
app.php
3. Dans le constructeur qui crée l'instance d'application (), enregistrez la liaison de base dans le conteneur, enregistrez tous les fournisseurs de services de base et enregistrez le nom de la catégorie principale dans le conteneur Application.php
3.1. Enregistrez les liaisons de base dans le conteneur
/** * Register the basic bindings into the container. * * @return void */ protected function registerBaseBindings() { static::setInstance($this); $this->instance('app', $this); $this->instance(Container::class, $this); $this->singleton(Mix::class); $this->instance(PackageManifest::class, new PackageManifest( new Filesystem, $this->basePath(), $this->getCachedPackagesPath() )); # 注:instance方法为将...注册为共享实例,singleton方法为将...注册为共享绑定 }
3.2 Enregistrez tous les fournisseurs de services de base (événements, journaux, routage)
protected function registerBaseServiceProviders() { $this->register(new EventServiceProvider($this)); $this->register(new LogServiceProvider($this)); $this->register(new RoutingServiceProvider($this)); }
3.3. dans le conteneur
4. Ce qui précède termine le chargement automatique des classes, l'enregistrement du fournisseur de services, la liaison de classe principale et la liaison d'enregistrement de base
5. Analyser la requête de
index.php //5.1 $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); //5.2 $response = $kernel->handle( $request = Illuminate\Http\Request::capture());
http
5.1. La méthode make consiste à analyser la valeur donnée à partir du conteneur $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); 中的Illuminate\Contracts\Http\Kernel::class 是在index.php 中的$app = require_once __DIR__.'/../bootstrap/app.php';这里面进行绑定的,实际指向的就是App\Http\Kernel::class这个类
5.2 Ici, la requête http est traitée
$response = $kernel->handle( $request = Illuminate\Http\Request::capture());
. et entre
Dans la classe représentée, nous pouvons voir qu'elle ne définit que du contenu lié au middleware, et il n'y a pas de méthode handle $kernel
AppHttpKernel.php
Cherchons la méthode handle dans sa classe parent
public function handle($request){ try { $request->enableHttpMethodParameterOverride(); // 最核心的处理http请求的地方【6】 $response = $this->sendRequestThroughRouter($request); } catch (Exception $e) { $this->reportException($e); $response = $this->renderException($request, $e); } catch (Throwable $e) { $this->reportException($e = new FatalThrowableError($e)); $response = $this->renderException($request, $e); } $this->app['events']->dispatch( new Events\RequestHandled($request, $response) ); return $response;}
use IlluminateFoundationHttpKernel as HttpKernel
6. Traiter les requêtes (lier à l'instance partagée et utiliser le mode pipeline pour traiter les requêtes des utilisateurs) Http
vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php的handle方法// 最核心的处理http请求的地方$response = $this->sendRequestThroughRouter($request);protected function sendRequestThroughRouter($request){ // 将请求$request绑定到共享实例 $this->app->instance('request', $request); // 将请求request从已解析的门面实例中清除(因为已经绑定到共享实例中了,没必要再浪费资源了) Facade::clearResolvedInstance('request'); // 引导应用程序进行HTTP请求 $this->bootstrap();【7、8】 // 进入管道模式,经过中间件,然后处理用户的请求【9、10】 return (new Pipeline($this->app)) ->send($request) ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware) ->then($this->dispatchToRouter());}
request
7, dans la méthode , exécutez le tableau de classes de démarrage donné , chargez les fichiers de configuration, les variables d'environnement, les fournisseurs de services, les façades, la gestion des exceptions et les fournisseurs de démarrage. Il s'agit d'une étape très importante, située à <.>bootstrap
/** * Bootstrap the application for HTTP requests. * * @return void */public function bootstrap(){ if (! $this->app->hasBeenBootstrapped()) { $this->app->bootstrapWith($this->bootstrappers()); }}
/** * 运行给定的引导类数组 * * @param string[] $bootstrappers * @return void */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]); }}/** * Get the bootstrap classes for the application. * * @return array */protected function bootstrappers(){ return $this->bootstrappers;}/** * 应用程序的引导类 * * @var array */protected $bootstrappers = [ // 加载环境变量 \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class, // 加载config配置文件【重点】 \Illuminate\Foundation\Bootstrap\LoadConfiguration::class, // 加载异常处理 \Illuminate\Foundation\Bootstrap\HandleExceptions::class, // 加载门面注册 \Illuminate\Foundation\Bootstrap\RegisterFacades::class, // 加载在config/app.php中的providers数组里所定义的服务【8 重点】 \Illuminate\Foundation\Bootstrap\RegisterProviders::class, // 记载引导提供者 \Illuminate\Foundation\Bootstrap\BootProviders::class,];
$bootstrappers
8. Chargez les services définis dans le tableau vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php
dans
Illuminate\Auth\AuthServiceProvider::class,Illuminate\Broadcasting\BroadcastServiceProvider::class,....../** * 自己添加的服务提供者 */\App\Providers\HelperServiceProvider::class,
config/app.php
Vous pouvez voir que les providers
et d'autres services couramment utilisés sont chargés ici9. Utilisez le mode pipeline pour traiter les demandes des utilisateurs, traitez-les d'abord et filtrez-les via le middleware
return (new Pipeline($this->app)) ->send($request) // 如果没有为程序禁用中间件,则加载中间件(位置在app/Http/Kernel.php的$middleware属性) ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware) ->then($this->dispatchToRouter());}
Redis、session、queue、auth、database、Route
app/Http/Kernel.php/** * 应用程序的全局HTTP中间件 * * These middleware are run during every request to your application. * * @var array */protected $middleware = [ \App\Http\Middleware\TrustProxies::class, \App\Http\Middleware\CheckForMaintenanceMode::class, \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, \App\Http\Middleware\TrimStrings::class, \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,];
10. effectuer la distribution des requêtes (y compris la recherche des routes correspondantes)
/** * 10.1 通过中间件/路由器发送给定的请求 * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ protected function sendRequestThroughRouter($request){ ... return (new Pipeline($this->app)) ... // 进行请求分发 ->then($this->dispatchToRouter());}
/** * 10.2 获取路由调度程序回调 * * @return \Closure */protected function dispatchToRouter(){ return function ($request) { $this->app->instance('request', $request); // 将请求发送到应用程序 return $this->router->dispatch($request); };}
/** * 10.3 将请求发送到应用程序 * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response|\Illuminate\Http\JsonResponse */ public function dispatch(Request $request){ $this->currentRequest = $request; return $this->dispatchToRoute($request);}
/** * 10.4 将请求分派到路由并返回响应【重点在runRoute方法】 * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response|\Illuminate\Http\JsonResponse */public function dispatchToRoute(Request $request){ return $this->runRoute($request, $this->findRoute($request));}
/** * 10.5 查找与给定请求匹配的路由 * * @param \Illuminate\Http\Request $request * @return \Illuminate\Routing\Route */protected function findRoute($request){ $this->current = $route = $this->routes->match($request); $this->container->instance(Route::class, $route); return $route;}
/** * 10.6 查找与给定请求匹配的第一条路由 * * @param \Illuminate\Http\Request $request * @return \Illuminate\Routing\Route * * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException */public function match(Request $request){ // 获取用户的请求类型(get、post、delete、put),然后根据请求类型选择对应的路由 $routes = $this->get($request->getMethod()); // 匹配路由 $route = $this->matchAgainstRoutes($routes, $request); if (! is_null($route)) { return $route->bind($request); } $others = $this->checkForAlternateVerbs($request); if (count($others) > 0) { return $this->getRouteForMethods($request, $others); } throw new NotFoundHttpException;}
Jusqu'à présent, la route correspondant à la demande a été trouvée et elle sera exécutée plus tard, ce qui est la méthode runRoute dans 10.4
/** * 10.7 返回给定路线的响应 * * @param \Illuminate\Http\Request $request * @param \Illuminate\Routing\Route $route * @return \Illuminate\Http\Response|\Illuminate\Http\JsonResponse */protected function runRoute(Request $request, Route $route){ $request->setRouteResolver(function () use ($route) { return $route; }); $this->events->dispatch(new Events\RouteMatched($route, $request)); return $this->prepareResponse($request, $this->runRouteWithinStack($route, $request) );}
/** * Run the given route within a Stack "onion" instance. * 10.8 在栈中运行路由,先检查有没有控制器中间件,如果有先运行控制器中间件 * * @param \Illuminate\Routing\Route $route * @param \Illuminate\Http\Request $request * @return mixed */protected function runRouteWithinStack(Route $route, Request $request){ $shouldSkipMiddleware = $this->container->bound('middleware.disable') && $this->container->make('middleware.disable') === true; $middleware = $shouldSkipMiddleware ? [] : $this->gatherRouteMiddleware($route); return (new Pipeline($this->container)) ->send($request) ->through($middleware) ->then(function ($request) use ($route) { return $this->prepareResponse( $request, $route->run() ); });}
/** * Run the route action and return the response. * 10.9 最后一步,运行控制器的方法,处理数据 * @return mixed */ public function run() { $this->container = $this->container ?: new Container; try { if ($this->isControllerAction()) { return $this->runController(); } return $this->runCallable(); } catch (HttpResponseException $e) { return $e->getResponse(); } }
11 , exécutez la route et renvoyez la réponse (souligné)
Comme vous pouvez le voir, il existe une méthode dans 10.7 appelée, qui crée une instance de réponse à partir d'une valeur donnée, tandis que la méthode
exécute la route sur la pile. En d'autres termes, la demande et la réponse de seront complétées ici.
Jusqu'à présent, l'ensemble du processus de fonctionnement du Laravel
framework a été analysé et le mystère du Laravel
framework a été dévoilé afin de le réaliser. la nature lisible de l'article, seul le code de base est donné. Vous devez lire le code source par vous-même en conjonction avec l'article. Il convient de noter que vous devez comprendre les connaissances préparatoires mentionnées dans l'article. en lisant le code source du framework. J'espère que vous gagnerez quelque chose et que vous vous en sortirez ! ! !
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!