1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 |
<?php //laravel 5.1.40 (LTS) //注册自动加载->初始化容器->注册基础事件、路由->注册http内核、console内核、异常处理内核->生成$request对象->http内核初始化->将$request副本扔给http内核处理(中间件处理、路由分发处理、结合用户自定义逻辑等)->处理完成生成一个$response->输出$response的相应信息->内核做一些中止操作 //入口文件->载入bootstrap下的autolad.php->载入vendor下的autoload.php //载入composer下的autoload_real.php实现composer的自动加载 //composer自动加载流程简介 //php版本>=5.6会调用autoload_static.php中的getInitializer方法(传入\Composer\Autoload\ClassLoader实例) //该方法返回一个匿名函数,然后在autoload_real.php中通过call_user_func调用它 //将autoload_static.php中的配置字段设置到\Composer\Autoload\ClassLoader的字段中 //然后auto_real.php继续往下走,调用\Composer\Autoload\ClassLoader的register方法 //该方法中通过spl_autoload_register来注册\Composer\Autoload\ClassLoader::loadClass方法实现自动加载 //继续走下去将autoload_static.php中的配置files全部加载进来(这里是直接加载,没有使用动态自动加载) //此时,加载核心文件和注册自动加载已经走完 //入口文件继续执行,加载/bootstrap/app.php->实例化laravel框架Applation(它继承laravel的Container容器) $app = new Illuminate\Foundation\Application( realpath(__DIR__.'/../') ); //构造函数中,做了如下几件事 //注册基础绑定,将Illuminate\Foundation\Application实例赋值给容器的静态字段$instance //同时将放入容器的instances字段数组,有2个key可以定位到它 'app' 和 'Illuminate\Container\Container' $this->registerBaseBindings(); //注册基础服务供应,事件服务供应和路由服务供应(两者都最终继承于Illuminate\Support\ServiceProvider) //注册过程中会实例化事件服务和路由服务实例,并将当前Application实例注入到它们的父类ServiceProvider的app字段 $this->registerBaseServiceProviders(); /******Application->registerBaseServiceProviders(EventServiceProvider实例) BEGIN******/ //注册事件过程简单分析,以EventServiceProvider为例 //Application.php中调用register方法,直接传入EventServiceProvider实例,同时会把Application对象注入到EventServiceProvider中 $this->register(new EventServiceProvider($this)); //register方法中首先会调用获取供应方法,此方法返回NULL,所以$registered=NULL if (($registered = $this->getProvider($provider)) && ! $force) { return $registered; } //getProvider方法会调用Illuminate\Support\Arr::first方法,由于此时Application的serviceProviders为空数组 //所以first方法中会直接调用value函数,返回NULL。value函数在composer的$files中载入/laravel/framework/src/Illuminate/Support/helpers.php return value($default); //继续走下去,会调用Illuminate\Support\ServiceProvider自己的register方法 //此方法会调用之前注入的Application的父类Container的singleton方法(翻译为:独生子女,表示单例) //然后会调用Application的bind方法,并告知为独生(单例)绑定 $this->bind('events', "<一个匿名函数,如下>", true); function ($app) { return (new Dispatcher($app))->setQueueResolver(function () use ($app) { return $app->make('Illuminate\Contracts\Queue\Factory'); }); }; //继续走下去,回到Aplication的register方法,标记事件服务供应已注册 $this->markAsRegistered($provider); //markAsRegistered方法第一行,$this['events'] 可以这样写是因为Application的父类Container实现了ArrayAccess接口 $this['events']->fire($class = get_class($provider), [$provider]); //接着会触发Container的offsetGet方法 return $this->make('events'); //然后继续调用Application的make方法(这里需要注意下,调用的是Application->make,不是Container->make。因为$this['events'],这里的$this指的是Application) //然而,在此处Application的make没有做任何操作,继续调用了Container的make。 //然后获取到$concrete是初始化时绑定的匿名函数Closure Object 关联 Illuminate\Events\EventServiceProvider Object $concrete = $this->getConcrete($abstract); //然后会走到 if($this->isBuildable($concrete, $abstract))的true分支中去,调用Container的build方法 $object = $this->build($concrete, $parameters); //然后在build方法的第一个if中直接调用刚才绑定的Closure Object 关联 Illuminate\Events\EventServiceProvider Object //第2个参数直接忽视,因为匿名函数只接收一个参数,php可以这么干 return $concrete($this, $parameters); //匿名函数中实例化了调度器或者说分发器 Illuminate\Events\Dispatcher 构造函数中注入了Application //并调用了调度器的设置队列解析器方法setQueueResolver,又传入了一个匿名函数,将其赋值给调度器的队列解析器字段$queueResolver function () use ($app) { return $app->make('Illuminate\Contracts\Queue\Factory'); } //然后将调度器的实例返回,赋值给上面的$object <$object = $this->build($concrete, $parameters);> //回到Container的make方法继续往下走,将调度器实例添加到instances中 $this->instances[$abstract] = $object; //继续往下走,调用解决回调方法,此时,与之相关的字段都为空 globalResolvingCallbacks、resolvingCallbacks、globalAfterResolvingCallbacks、afterResolvingCallbacks //所有没有任何回调需要解决,该方法什么也不做 $this->fireResolvingCallbacks($abstract, $object); //继续往下走,在resolved字段标记events为(已解决) $this->resolved[$abstract] = true; //最终在make中返回调度器实例->offsetGet->$this['events'],然后调用它的fire方法(回到Application的markAsRegistered方法) //其实这步什么也没有做,fire可以理解为发射、触发,然而此时调度器中没有任何事件监听需要触发 $this['events']->fire($class = 'Illuminate\Events\EventServiceProvider', ["Illuminate\Events\EventServiceProvider的实例"]); //继续往下走,将Illuminate\Events\EventServiceProvider的实例放入Application的服务供应serviceProviders字段中 //然后在已加载的供应loadedProviders字段中标记为true $this->loadedProviders['Illuminate\Events\EventServiceProvider'] = true; /******Application->registerBaseServiceProviders(EventServiceProvider实例) END******/ /******Application->registerBaseServiceProviders(RoutingServiceProvider实例) BEGIN******/ //有些流程和EventServiceProvider类似的就不在详述了 //路由服务供应者注册后,会调用以下这些子方法 RoutingServiceProvider-register() { $this->registerRouter(); $this->registerUrlGenerator(); $this->registerRedirector(); $this->registerPsrRequest(); $this->registerPsrResponse(); $this->registerResponseFactory(); } //registerRouter方法会触发Container的offsetSet方法绑定router $this->app['router'] = $this->app->share(function ($app) { return new Router($app['events'], $app); }); //先执行Container的share方法,还是返回一个匿名函数 //所以变成了Container->bind("router", "share中返回的匿名函数(它的参数也是个匿名函数)") //然后在bind方法中将其,绑定到Container的bindings字段中 $this->bindings['router'] = compact('share中返回的匿名函数', 'shared为false'); //同理,通过share方法绑定了url和redirect。share方法其实是一个"双重匿名的单例" //例如:$test=share(Closure); $a=$test(); $b=$test(); 此时$a和$b公用一个实例 //接着分别绑定(bind)PsrRequest、PsrResponse和单例绑定(singleton)ResponseFactory /******Application->registerBaseServiceProviders(RoutingServiceProvider实例) END******/ //此时,注册基础服务供应完成了,回到Application->__construct()继续注册核心容器别名 //这步很简单,就是将Application中一些固定配置的别名定义,遍历添加到Container的aliases容器中 $this->registerCoreContainerAliases(); //接着往下走,开始设置一些基础路径 例如项目根目录为:/home/wwwroot/lt lt=laravel test if ("/home/wwwroot/lt") { $this->setBasePath($basePath); } //然后在容器中注册一些路径(应用目录、项目根目录、配置文件目录、数据库目录、语言相关目录、网站入口目录、存储目录,相关文件缓存等) //此时,实例化Illuminate\Foundation\Application完成,回到bootstrap中的app.php,继续往下走,分别注册3个单例(web内核、命令行内核、异常处理内核) $app->singleton( 'Illuminate\Contracts\Http\Kernel', 'App\Http\Kernel' ); $app->singleton( 'Illuminate\Contracts\Console\Kernel', 'App\Console\Kernel' ); $app->singleton( 'Illuminate\Contracts\Debug\ExceptionHandler', 'App\Exceptions\Handler' ); //以http内核为例,走到Container的bind方法后,由于$concrete是一个字符串,所以进入了getClosure方法 if (! $concrete instanceof Closure) { $concrete = $this->getClosure($abstract, $concrete); } //Container->getClosure返回了一个匿名函数,然后绑定到Container的bindings容器中 //然后会回到index.php调用Application->make('Illuminate\Contracts\Http\Kernel'); //然后会进入Container的build方法,执行刚才绑定的匿名函数 $this->bindings['Illuminate\Contracts\Http\Kernel']['concrete']("Container自身实例",[]); //执行匿名函数时,会进行再次build,但是这次的参数$concrete=string("App\Http\Kernel"),进入build后不会直接返回执行匿名函数,而是进行反射 $reflector = new ReflectionClass($concrete); //如果反射失败,直接抛异常 if (! $reflector->isInstantiable()) { throw new BindingResolutionContractException($message); } //然后将其暂放入建造堆栈容器中,没用到或用完后会array_pop掉 $this->buildStack[] = $concrete; //如果反射类没有构造函数,直接把它new出来并返回,如果有父类需要检查父类是否有构造函数 $constructor = $reflector->getConstructor(); if (is_null($constructor)) { //这里没有用到buildStack,直接array_pop掉 array_pop($this->buildStack); return new $concrete; } //如果有构造函数,获取构造函数参数是ReflectionParameter的数组,如:array(0=>ReflectionParameter Object, 1=>ReflectionParameter Object ...) $dependencies = $constructor->getParameters(); //接着走下去,keyParametersByArgument没有干任何事,继续往下调用getDependencies方法 $instances = $this->getDependencies( $dependencies, $parameters ); //进入getDependencies,根据当前参数,会调用resolveClass方法 foreach (array("ReflectionParameter Object app","ReflectionParameter Object router") as $parameter) { $dependencies[] = $this->resolveClass($parameter); } //然后进入resolveClass方法,会再次进入Application的make方法,先说ReflectionParameter Object app return $this->make("Illuminate\Contracts\Foundation\Application"); //此时,回到Application->make()方法,由于注册过别名,所以$abstract变成了其别名:app //然后继续调用Container->make("app",[]); //然后在Container->instances中找到了'app'对应的实例 Illuminate\Foundation\Application Object ... //然后回到Container的getDependencies方法,将实例添加到$dependencies数组 //然后进入下一次循环,再次调用Application->make return $this->make('Illuminate\Routing\Router'); //然后别名后调用Container->make return parent::make('router', []); //然后进入build方法,得到之前绑定的匿名函数$this->bindings['router']['concrete'] //继续往下走,在resolved字段标记router为(已解决) $this->resolved[$abstract] = true; //然后回到Container的getDependencies方法,将匿名函数添加到$dependencies数组 //然后返回$dependencies数组,回到build方法 //然后释放掉buildStack,这里其实并没有用到它 array_pop($this->buildStack); //然后,调用反射类的实例方法,传入刚才返回的$dependencies数组 return $reflector->newInstanceArgs($instances); //然后一路返回至Container->make中的第一次build处 "App\Http\Kernel Object" = $this->build("Illuminate\Contracts\Http\Kernel", []); //然后继续走下去,将刚才反射出来的"App\Http\Kernel Object"放入instances容器 if ($this->isShared("Illuminate\Contracts\Http\Kernel") == true) { $this->instances["Illuminate\Contracts\Http\Kernel"] = "App\Http\Kernel Object"; } //继续往下走,在resolved字段标记Illuminate\Contracts\Http\Kernel为(已解决) $this->resolved[$abstract] = true; //此时,make("Illuminate\Contracts\Http\Kernel")完成了,回到index.php //继续执行,调用父类Illuminate\Foundation\Http\Kernel\handle方法,需要传入request参数 $response = $kernel->handle( $request = Illuminate\Http\Request::capture() ); //然后进入获取$request对象流程,laravel的Request底层使用了symfony组件, //调用Symfony\Component\HttpFoundation\Request的静态方法,将其静态字段标记为true //$httpMethodParameterOverride,大致意思为:http方法参数重写 static::enableHttpMethodParameterOverride(); //然后回到capture方法,capture翻译为:捕获,调用Illuminate\Http\Request的createFromBase方法 return static::createFromBase(SymfonyRequest::createFromGlobals()); //此时,需要先通过SymfonyRequest将$_GET、$_POST、$_COOKIE、$_FILES、$_SERVER等全局变量封装到它的相关字段中并将其自身实例化 //$_GET==$query $_POST==$request $_COOKIE==$cookies $_FILES==$files $_SERVER==$server //调用createFromGlobals再调用createRequestFromFactory($_GET, $_POST, array(), $_COOKIE, $_FILES, $server) //然后进入createRequestFromFactory方法会调用new static,跟new get_class($this)效果类似 //实例化了Symfony\Component\HttpFoundation\Request return new static($query, $request, $attributes, $cookies, $files, $server, $content); //然后进入Symfony\Component\HttpFoundation\Request的__construct调用initialize方法 $this->initialize($query, $request, $attributes, $cookies, $files, $server, $content); //然后将各个参数封装成ParameterBag对象或者继承ParameterBag的对象Symfony\Component\HttpFoundation\Request的各个相关字段 //然后会进入Illuminate\Http\Request->createFromBase并将刚才实例化的SymfonyRequest传入 //这个判断不会进入,因为调用方是子类,而$request是通过父类的new static延迟静态绑定的 if ($request instanceof static) { return $request; } //然后通过(new static)->duplicate,实例化自己Illuminate\Http\Request,并调用duplicate方法,duplicate中调用了父类的duplicate //duplicate是复制的意思,把Illuminate\Http\Request复制一份,赋值相应参数,并返回 //然后走下去,将$request->request 重置为 GET|POST|JSON(如果是json的话,会转成array)的参数,并返回 //此时回到了index.php,进入$kernel的handle方法,传入Illuminate\Http\Request的副本 //将副本的$httpMethodParameterOverride设置为ture,并调用Kernel的sendRequestThroughRouter方法 //然后设置Container的instances字段容器"request"=>"Illuminate\Http\Request副本" //然后进行初始化,$this->bootstrap() $bootstrappers = [ 'Illuminate\Foundation\Bootstrap\DetectEnvironment', /*检查环境 使用Dotenv做一些初始化环境配置 将/.env加载到$_SERVER $_ENV中, 然后绑定$app->bindings['env'] = 一个匿名函数返回APP_ENV的值 */ 'Illuminate\Foundation\Bootstrap\LoadConfiguration', /*加载配置 将/config下的配置文件全部加载到Illuminate\Config\Repository的items中, 并将Illuminate\Config\Repository Object放入Application->instances['config'], 设置时区、编码等 */ 'Illuminate\Foundation\Bootstrap\ConfigureLogging', /*日志配置 实例化Illuminate\Log\Writer(注入Monolog和$app->bindings["events"]), 并将其注册到$app->instances['log'],然后初始化日志方式(文件)、路径、格式(format)等 */ 'Illuminate\Foundation\Bootstrap\HandleExceptions', //设置错误日志级别、设置自定义错误处理、设置自定义异常处理、设置自定义shutdown处理等 'Illuminate\Foundation\Bootstrap\RegisterFacades', /*设置别名自动加载 在spl_autoload_register函数队列首部插入别名加载class_alias, 如果new的类名是config/app.php中的aliases数组的key,将key作为value的别名 */ 'Illuminate\Foundation\Bootstrap\RegisterProviders', //通过Illuminate\Foundation\ProviderRepository注册services.json下的相关服务供应商 'Illuminate\Foundation\Bootstrap\BootProviders', //执行收尾工作,如果$app->serviceProviders有boot方法,调用相应的boot方法 ]; $this->app->bootstrapWith($bootstrappers); //进入bootstrapWith方法,循环将$bootstrappers做相应初始化 foreach ($bootstrappers as $bootstrapper) { //在初始化之前挂载事件监听,暂时什么都不干 $this['events']->fire('bootstrapping: '.$bootstrapper, [$this]); //这一步,实例化相应的对象,并在容器中将它标识为已解决 $this->resolved[$abstract] = true; //然后调用对象的初始化方法 $obj->bootstrap(Application $app); $this->make($bootstrapper)->bootstrap($this); //在初始化之前挂载事件监听,暂时什么都不干 $this['events']->fire('bootstrapped: '.$bootstrapper, [$this]); } //初始化完成后,回到Illuminate\Foundation\Http\Kernel->handle()->sendRequestThroughRouter() //然后实例化Illuminate\Pipeline\Pipeline并做相应操作 pipeline流程 输入->管道加工->输出 //构造函数传入$app,send传入传输参数($request),through传入需要经过的加工处理的管道|流水线($middleware中间件),then执行相应的目标方法 return (new Pipeline($this->app)) ->send($request) ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware) ->then($this->dispatchToRouter()); //send和through只是一些设置工作,then方法比较复杂,详细说一下then方法 //$firstSlice可以理解为Illuminate\Foundation\Http\Kernel->dispatchToRouter()返回的匿名函数 $firstSlice = $this->getInitialSlice($destination); //将如下数组($this->pipes)倒序排序,因为下面call_user_func的时候是从匿名函数的最里层开始调用的 array ( 'Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode', 'App\Http\Middleware\EncryptCookies', 'Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse', 'Illuminate\Session\Middleware\StartSession', 'Illuminate\View\Middleware\ShareErrorsFromSession', 'App\Http\Middleware\VerifyCsrfToken', ) $pipes = array_reverse($this->pipes); // $pipes上面的数组倒序、$this->getSlice()返回一个匿名函数、$firstSlice也是一个匿名函数,$this->passable就是$request // array_reduce($pipes, $this->getSlice(), $firstSlice)返回一个递归后的匿名函数。 return call_user_func( array_reduce($pipes, $this->getSlice(), $firstSlice), $this->passable ); //执行call_user_func后会依次执行对上面的array中的类名进行make->build->反射->调用其handle方法,handle的参数是$request和$firstSlice或上一次执行的返回值 //首先调用$firstSlice,其实就是Illuminate\Routing\Router的dispatch方法 //然后进入dispatch方法,刚开始$response为NULL,将$request分发到路由后返回Response $response = $this->dispatchToRoute($request); //然后findRoute、然后Illuminate\Routing\RouteCollection->match $route = $this->findRoute($request); $this->routes->match($request); //进入match方法 $routes = $this->get($request->getMethod()); //然后会走到Illuminate\Support\Arr::get方法 return Arr::get($this->routes, $method, []); //Arr::get()中第一个参数$this->routes是之前Illuminate\Foundation\Bootstrap\BootProviders->bootstrap()的时候赋值的 //App\Providers\RouteServiceProvider->boot() //$this->app[UrlGenerator::class]->setRootControllerNamespace($this->namespace); //UrlGenerator::class => Illuminate\Contracts\Routing\UrlGenerator 别名为url //然后会执行Illuminate\Routing\RoutingServiceProvider->registerUrlGenerator绑定的匿名函数 //然后回到App\Providers\RouteServiceProvider->boot()进入$this->loadRoutes(); //然后调用$this->app->call([$this, 'map']); return call_user_func_array($callback, $dependencies); //然后会调用App\Providers\RouteServiceProvider->map() $router->group(['namespace' => $this->namespace], function ($router) { require app_path('Http/routes.php'); }); //然后在Illuminate\Routing\Router->group()中给groupStack赋值 $this->groupStack[] = array("namespace" => "App\Http\Controllers"); //并载入/home/wwwroot/lt/app/Http/routes.php Route::get('/', function () { return view('welcome'); }); //Illuminate\Routing\Router->get()->addRoute() return $this->routes->add($this->createRoute(['GET', 'HEAD'], '/', function(){return view('welcome');})); //Illuminate\Routing\Router->createRoute() $route = $this->newRoute($methods, $this->prefix($uri), $action); //Illuminate\Routing\Router->newRoute() return (new Route($methods, $uri, $action))->setContainer($this->container); //Illuminate\Routing\Router->createRoute()->mergeWithLastGroup()->mergeGroup() $this->mergeGroupAttributesIntoRoute($route); $route->setAction($action); //Illuminate\Routing\Router->createRoute() $this->addWhereClausesToRoute($route); //Illuminate\Routing\RouteCollection->add $this->addToCollections($route); //Illuminate\Routing\RouteCollection->addToCollections //该方法中为$this->routes赋值(上面有提到过),并为allRoutes赋值(foreach的最后一个key.$domainAndUri) $domainAndUri = $route->domain().$route->getUri(); foreach ($route->methods() as $method) { $this->routes[$method][$domainAndUri] = $route; } $this->allRoutes[$method.$domainAndUri] = $route; //Illuminate\Routing\RouteCollection->add->addLookups 如果设置别名或者controller作相应处理 //回到Illuminate\Routing\RouteCollection->match,$routes=array("/"=>Illuminate\Routing\Route Object) $routes = $this->get($request->getMethod()); $route = $this->check($routes, $request); //Illuminate\Routing\RouteCollection->match->check return Arr::first($routes, function ($key, $value) use ($request, $includingMethod) { return $value->matches($request, $includingMethod); }); //Illuminate\Routing\Route->matches $this->compileRoute(); //Illuminate\Routing\Route->compileRoute $this->compiled = with( new SymfonyRoute($uri, $optionals, $this->wheres, [], $this->domain() ?: '') )->compile(); //Symfony\Component\Routing\Route->compile 返回一个Symfony\Component\Routing\CompiledRoute Object return $this->compiled = Symfony\Component\Routing\RouteCompiler::compile($this); //Illuminate\Routing\RouteCollection->match 做一些相应的绑定操作,然后返回Illuminate\Routing\Route Object return $route->bind($request); //然后回到Illuminate\Routing\Router->findRoute方法,将match返回的Illuminate\Routing\Route Object赋值给$this->current并注册到$app->instances $this->container->instance('Illuminate\Routing\Route', $route); //然后回到Illuminate\Routing\Router->dispatchToRoute()继续往下走,$request->setRouteResolver()后,生成$response对象 $response = $this->runRouteWithinStack($route, $request); //进入Illuminate\Routing\Router->runRouteWithinStack,再来一次pipeline流程,但是这次中间件$middleware为空,所以只是执行then中的匿名函数并返回 return (new Pipeline($this->container)) ->send($request) ->through($middleware) ->then(function ($request) use ($route) { return $this->prepareResponse( $request, $route->run($request) ); }); //执行return $this->prepareResponse($request, $route->run($request)); 先执行 $route->run($request) //会调用 lt/app/http/routes.php中的 return view('welcome'); //然后调用helpers.php中的view函数,然后会调用$app->make("Illuminate\Contracts\View\Factory") //Illuminate\Contracts\View\Factory的别名是view,所以会执行之前初始化时候绑定的$app->bindings['view']所对应的匿名函数 //Closure Object 关联 Illuminate\View\ViewServiceProvider Object //然后会执行 $app['view.engine.resolver'] 返回Illuminate\View\EngineResolver Object 并给它的resolvers字段设置2个匿名函数并在$app中注册一个blade.compiler绑定 //$engine->resolvers['php']=Closure Object 关联 Illuminate\View\ViewServiceProvider Object //$engine->resolvers['blade']=Closure Object 关联 Illuminate\View\ViewServiceProvider Object //然后执行 $app['view.finder'] 返回Illuminate\View\FileViewFinder Object //然后实例化Illuminate\View\Factory $env = new Factory('Illuminate\View\EngineResolver Object', 'Illuminate\View\FileViewFinder Object', 'Illuminate\Events\Dispatcher Object'); //然后回到helpers.php的view函数($factory就是上面返回的$env) return $factory->make($view, $data, $mergeData); //找到welcome文件的路径 /home/wwwroot/lt/resources/views/welcome.blade.php $path = $this->finder->find($view); //然后继续往下走会返回一个view对象 $this->callCreator($view = new View($this, $this->getEngineFromPath($path), $view, $path, $data)); return $view; //$this->getEngineFromPath($path) 会执行刚才绑定的$engine->resolvers['blade']的匿名函数 //匿名函数返回一个Illuminate\View\Engines\CompilerEngine Object //该对象注入了 Illuminate\View\Compilers\BladeCompiler Object //回到Illuminate\Routing\Router->prepareResponse 实例化Illuminate\Http\Response extends Symfony\Component\HttpFoundation\Response $response = new Response('Illuminate\View\View Object'); //然后预处理下$request并返回Response对象 return $response->prepare($request); //然后回到Illuminate\Routing\Router->dispatchToRoute 后续操作暂时都没执行 return $response; //然后回到最上面的pipeline流程 //调用Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode的handle //检查/home/wwwroot/lt/storage/framework/down是否存在,有就返回503错误 //调用App\Http\Middleware\EncryptCookies对cookie进行加解密 //调用Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse //调用Illuminate\Session\Middleware\StartSession进行session驱动设置,session_start等 //调用Illuminate\View\Middleware\ShareErrorsFromSession //调用App\Http\Middleware\VerifyCsrfToken验证CSFR令牌 //然后返回经过流水线处理的$response对象,回到index.php,输出头信息和内容,此时会输出laravel的welcome页面 $response->send(); //最后做一些后续操作,之前用到的中间件如果有terminate方法,执行它 //这里只有Illuminate\Session\Middleware\StartSession有terminate方法,执行它做一些SESSION的后续操作 //laravel中操作session是在内存中(对象)操作的,最后结束时将其"持久化"到文件中 $kernel->terminate($request, $response); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 |
<?php class Container{ protected $instances = []; //存放初始化的实例 protected $bindings = []; //存放初始化的绑定 protected $aliases = []; //存放类名的别名 类名=>别名 protected $reboundCallbacks = []; //存放反弹回调的匿名函数 protected $afterResolvingCallbacks = []; //存放延迟解决的匿名函数 protected $deferredServices = []; //存放延迟服务 Illuminate\Foundation\ProviderRepository->load->services.json->deferred数组 protected $basePath = "项目根目录"; //例如:/home/wwwroot/lt(最后边没有/,Application->setBasePath()中设置) public function initInstances() { $this->instances = array( // 下面2个是在,Application的registerBaseBindings()中注册绑定的 // 在它父类中instances容器中,绑定自己,取了2个别名 'app' => 'Illuminate\Foundation\Application Object ...', 'Illuminate\Container\Container' => 'Illuminate\Foundation\Application Object ...', // Application的registerBaseServiceProviders方法->register()->markAsRegistered()->$this['events']->触发Container->offsetGet() // ->make()->build()->触发EventServiceProvider的register中的匿名函数->return回调度器方法->Container的make方法中添加进来 'events' => 'Illuminate\Events\Dispatcher Object', 'path' => '/home/wwwroot/lt/app', //应用目录 'path.base' => '/home/wwwroot/lt', //项目根目录 'path.config' => '/home/wwwroot/lt/config', //配置文件目录 'path.database' => '/home/wwwroot/lt/database', //数据库目录 'path.lang' => '/home/wwwroot/lt/resources/lang', //语言相关目录 'path.public' => '/home/wwwroot/lt/public', //网站入口目录 'path.storage' => '/home/wwwroot/lt/storage', //存储目录,相关文件缓存等 "Illuminate\Contracts\Http\Kernel" => "App\Http\Kernel Object", //入口文件中$app->make处注册的HTTP内核实例 "request" => "Illuminate\Http\Request Object", //Illuminate\Foundation\Http\Kernel->handle()->sendRequestThroughRouter()注册 "config" => "Illuminate\Config\Repository Object", //Illuminate\Foundation\Bootstrap\LoadConfiguration->bootstrap()注册 "log" => "Illuminate\Log\Writer Object", //Illuminate\Foundation\Bootstrap\ConfigureLogging->bootstrap()注册 "Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode" => "Object", //通过pipeline注册 "routes" => "Illuminate\Routing\RouteCollection Object", //执行Illuminate\Routing\RoutingServiceProvider->registerUrlGenerator的匿名函数注册 "Illuminate\Routing\Route" => "Illuminate\Routing\Route Object", //Illuminate\Routing\Router->findRoute()中注册 ); } public function initBindings() { $this->bindings = array( //下面这个是在Container->bind()中$this->bindings[$abstract] = compact('concrete', 'shared'); //注册了一个事件绑定,concrete(混凝土)是一个匿名函数,可能表示匿名函数比较"百搭"吧,你怎么实现,它怎么执行。。 //shared为1表示已被分享的,表示单例(基于$this->bindings容器,或者说基于$this->instances) //当$this->bindings[$key]["shared"]为1时,可以在$this->bindings[$key]中找到相应的实例 'events' => array( 'concrete' => 'Closure Object 关联 Illuminate\Events\EventServiceProvider Object', 'shared' => 1 ), //下面3个是在Illuminate\Routing\RoutingServiceProvider->register()->触发offsetSet()并使用share方法绑定进来的 //他们的concrete回调函数是不同的,只是都与Illuminate\Routing\RoutingServiceProvider Object相关 //share方法,表示分享,也表示单例(基于匿名函数的返回对象) //$a=$this->bindings[$key]['concrete']; $b=$this->bindings[$key]['concrete']; $a()和$b()是同一个"东西"; 'router' => array( 'concrete' => 'Closure Object 关联 Illuminate\Routing\RoutingServiceProvider Object', 'shared' => 0 ), 'url' => array( 'concrete' => 'Closure Object 关联 Illuminate\Routing\RoutingServiceProvider Object', 'shared' => 0 ), 'redirect' => array( 'concrete' => 'Closure Object 关联 Illuminate\Routing\RoutingServiceProvider Object', 'shared' => 0 ), //下面2个同上是触发offsetSet()绑定的,但是它们直接使用了Container的bind方法 'Psr\Http\Message\ServerRequestInterface' => array( 'concrete' => 'Closure Object 关联 Illuminate\Routing\RoutingServiceProvider Object', 'shared' => 0 ), 'Psr\Http\Message\ResponseInterface' => array( 'concrete' => 'Closure Object 关联 Illuminate\Routing\RoutingServiceProvider Object', 'shared' => 0 ), //下面这个同上是触发offsetSet()绑定的,但是它使用了Container的singleton方法 'Illuminate\Contracts\Routing\ResponseFactory' => array( 'concrete' => 'Closure Object 关联 Illuminate\Routing\RoutingServiceProvider Object', 'shared' => 1 ), //下面3个是bootstrap中的app.php中调用Application->singleton()绑定的 'Illuminate\Contracts\Http\Kernel' => array( 'concrete' => 'Closure Object use了Illuminate\Contracts\Http\Kernel和App\Http\Kernel(还未make)', 'shared' => 1 ), 'Illuminate\Contracts\Console\Kernel' => array( 'concrete' => 'Closure Object use了Illuminate\Contracts\Console\Kernel和App\Console\Kernel(还未make)', 'shared' => 1 ), 'Illuminate\Contracts\Debug\ExceptionHandler' => array( 'concrete' => 'Closure Object use了Illuminate\Contracts\Debug\ExceptionHandler和App\Exceptions\Handler(还未make)', 'shared' => 1 ), //下面这个是build Illuminate\Contracts\Http\Kernel的时候注入的Illuminate\Routing\Router的构造函数中绑定的 '_missing' => array( 'concrete' => 'Closure Object 关联Illuminate\Routing\Router Object', 'shared' => 0 ), //下面这个是Illuminate\Foundation\Bootstrap\DetectEnvironment->bootstrap(),然后调用$app->detectEnvironment绑定的 "env" => array( 'concrete' => 'Closure Object 调用后只是返回一个APP_ENV的环境变量', 'shared' => 0 ), //下面这几个是$app->bootstrapWith(),然后在foreach中轮询到Illuminate\Foundation\Bootstrap\RegisterProviders->bootstrap(), //然后遍历实例化/bootstrap/cache/services.json中的eager数组中的相关类后调用register注册的 "auth" => array( 'concrete' => 'Closure Object 关联 Illuminate\Auth\AuthServiceProvider Object', 'shared' => 1 ), "auth.driver" => array( 'concrete' => 'Closure Object 关联 Illuminate\Auth\AuthServiceProvider Object', 'shared' => 1 ), "Illuminate\Contracts\Auth\Authenticatable" => array( 'concrete' => 'Closure Object 关联 Illuminate\Auth\AuthServiceProvider Object', 'shared' => 0 ), "Illuminate\Contracts\Auth\Access\Gate" => array( 'concrete' => 'Closure Object 关联 Illuminate\Auth\AuthServiceProvider Object', 'shared' => 1 ), "illuminate.route.dispatcher" => array( 'concrete' => 'Closure Object 关联 Illuminate\Routing\ControllerServiceProvider Object', 'shared' => 1 ), "cookie" => array( 'concrete' => 'Closure Object 关联 Illuminate\Cookie\CookieServiceProvider Object', 'shared' => 1 ), "Faker\Generator" => array( 'concrete' => 'Closure Object 关联 Illuminate\Database\DatabaseServiceProvider Object', 'shared' => 1 ), "Illuminate\Database\Eloquent\Factory" => array( 'concrete' => 'Closure Object 关联 Illuminate\Database\DatabaseServiceProvider Object', 'shared' => 1 ), "Illuminate\Contracts\Queue\EntityResolver" => array( 'concrete' => 'Closure Object 关联 Illuminate\Database\DatabaseServiceProvider Object', 'shared' => 1 ), "db.factory" => array( 'concrete' => 'Closure Object 关联 Illuminate\Database\DatabaseServiceProvider Object', 'shared' => 1 ), "db" => array( 'concrete' => 'Closure Object 关联 Illuminate\Database\DatabaseServiceProvider Object', 'shared' => 1 ), "db.connection" => array( 'concrete' => 'Closure Object 关联 Illuminate\Database\DatabaseServiceProvider Object', 'shared' => 0 ), "encrypter" => array( 'concrete' => 'Closure Object 关联 Illuminate\Encryption\EncryptionServiceProvider Object', 'shared' => 1 ), "files" => array( 'concrete' => 'Closure Object 关联 Illuminate\Filesystem\FilesystemServiceProvider Object', 'shared' => 1 ), "filesystem" => array( 'concrete' => 'Closure Object 关联 Illuminate\Filesystem\FilesystemServiceProvider Object', 'shared' => 1 ), "filesystem.disk" => array( 'concrete' => 'Closure Object 关联 Illuminate\Filesystem\FilesystemServiceProvider Object', 'shared' => 1 ), "filesystem.cloud" => array( 'concrete' => 'Closure Object 关联 Illuminate\Filesystem\FilesystemServiceProvider Object', 'shared' => 1 ), //"Illuminate\Foundation\Providers\FoundationServiceProvider","Illuminate\Pagination\PaginationServiceProvider" //上面2个没有绑定进bindings,而是在自己的相关类中注册实例或者绑定回调 "session" => array( 'concrete' => 'Closure Object 关联 Illuminate\Session\SessionServiceProvider Object', 'shared' => 1 ), "session.store" => array( 'concrete' => 'Closure Object 关联 Illuminate\Session\SessionServiceProvider Object', 'shared' => 1 ), "Illuminate\Session\Middleware\StartSession" => array( 'concrete' => 'Closure Object 关联 Illuminate\Foundation\Application Object use了Illuminate\Session\Middleware\StartSession', 'shared' => 1 ), "validation.presence" => array( 'concrete' => 'Closure Object 关联 Illuminate\Validation\ValidationServiceProvider Object', 'shared' => 1 ), "validator" => array( 'concrete' => 'Closure Object 关联 Illuminate\Validation\ValidationServiceProvider Object', 'shared' => 1 ), "view.engine.resolver" => array( 'concrete' => 'Closure Object 关联 Illuminate\View\ViewServiceProvider Object', 'shared' => 1 ), "view.finder" => array( 'concrete' => 'Closure Object 关联 Illuminate\View\ViewServiceProvider Object', 'shared' => 0 ), "view" => array( 'concrete' => 'Closure Object 关联 Illuminate\View\ViewServiceProvider Object', 'shared' => 1 ), "blade.compiler" => array( 'concrete' => 'Closure Object 关联 Illuminate\View\ViewServiceProvider Object', 'shared' => 1 ), ); } public function initAliases() { //这步很简单,Application构造函数中调用registerCoreContainerAliases,会把一些固定配置的别名定义,遍历添加到Container的aliases容器中 $this->aliases = array ( 'Illuminate\Foundation\Application' => 'app', 'Illuminate\Contracts\Container\Container' => 'app', 'Illuminate\Contracts\Foundation\Application' => 'app', 'Illuminate\Auth\AuthManager' => 'auth', 'Illuminate\Auth\Guard' => 'auth.driver', 'Illuminate\Contracts\Auth\Guard' => 'auth.driver', 'Illuminate\Auth\Passwords\TokenRepositoryInterface' => 'auth.password.tokens', 'Illuminate\View\Compilers\BladeCompiler' => 'blade.compiler', 'Illuminate\Cache\CacheManager' => 'cache', 'Illuminate\Contracts\Cache\Factory' => 'cache', 'Illuminate\Cache\Repository' => 'cache.store', 'Illuminate\Contracts\Cache\Repository' => 'cache.store', 'Illuminate\Config\Repository' => 'config', 'Illuminate\Contracts\Config\Repository' => 'config', 'Illuminate\Cookie\CookieJar' => 'cookie', 'Illuminate\Contracts\Cookie\Factory' => 'cookie', 'Illuminate\Contracts\Cookie\QueueingFactory' => 'cookie', 'Illuminate\Encryption\Encrypter' => 'encrypter', 'Illuminate\Contracts\Encryption\Encrypter' => 'encrypter', 'Illuminate\Database\DatabaseManager' => 'db', 'Illuminate\Database\Connection' => 'db.connection', 'Illuminate\Database\ConnectionInterface' => 'db.connection', 'Illuminate\Events\Dispatcher' => 'events', 'Illuminate\Contracts\Events\Dispatcher' => 'events', 'Illuminate\Filesystem\Filesystem' => 'files', 'Illuminate\Filesystem\FilesystemManager' => 'filesystem', 'Illuminate\Contracts\Filesystem\Factory' => 'filesystem', 'Illuminate\Contracts\Filesystem\Filesystem' => 'filesystem.disk', 'Illuminate\Contracts\Filesystem\Cloud' => 'filesystem.cloud', 'Illuminate\Contracts\Hashing\Hasher' => 'hash', 'Illuminate\Translation\Translator' => 'translator', 'Symfony\Component\Translation\TranslatorInterface' => 'translator', 'Illuminate\Log\Writer' => 'log', 'Illuminate\Contracts\Logging\Log' => 'log', 'Psr\Log\LoggerInterface' => 'log', 'Illuminate\Mail\Mailer' => 'mailer', 'Illuminate\Contracts\Mail\Mailer' => 'mailer', 'Illuminate\Contracts\Mail\MailQueue' => 'mailer', 'Illuminate\Auth\Passwords\PasswordBroker' => 'auth.password', 'Illuminate\Contracts\Auth\PasswordBroker' => 'auth.password', 'Illuminate\Queue\QueueManager' => 'queue', 'Illuminate\Contracts\Queue\Factory' => 'queue', 'Illuminate\Contracts\Queue\Monitor' => 'queue', 'Illuminate\Contracts\Queue\Queue' => 'queue.connection', 'Illuminate\Routing\Redirector' => 'redirect', 'Illuminate\Redis\Database' => 'redis', 'Illuminate\Contracts\Redis\Database' => 'redis', 'Illuminate\Http\Request' => 'request', 'Illuminate\Routing\Router' => 'router', 'Illuminate\Contracts\Routing\Registrar' => 'router', 'Illuminate\Session\SessionManager' => 'session', 'Illuminate\Session\Store' => 'session.store', 'Symfony\Component\HttpFoundation\Session\SessionInterface' => 'session.store', 'Illuminate\Routing\UrlGenerator' => 'url', 'Illuminate\Contracts\Routing\UrlGenerator' => 'url', 'Illuminate\Validation\Factory' => 'validator', 'Illuminate\Contracts\Validation\Factory' => 'validator', 'Illuminate\View\Factory' => 'view', 'Illuminate\Contracts\View\Factory' => 'view', ); } public function initReboundCallbacks() { $this->reboundCallbacks = array( 'request' => array( //Illuminate\Auth\AuthServiceProvider->register()->registerRequestRebindHandler()注册 'Closure Object 关联 Illuminate\Auth\AuthServiceProvider Object', //执行Illuminate\Routing\RoutingServiceProvider->registerUrlGenerator()的匿名函数注册 'Closure Object 关联 Illuminate\Routing\RoutingServiceProvider Object', ), 'routes' => array( //执行Illuminate\Routing\RoutingServiceProvider->registerUrlGenerator()的匿名函数注册 'Illuminate\Routing\RoutingServiceProvider Object', ), ); } public function initAfterResolvingCallbacks() { //Illuminate\Foundation\Bootstrap\RegisterProviders->service.json->eager->Illuminate\Validation\ValidationServiceProvider绑定 $this->afterResolvingCallbacks = array( 'Illuminate\Contracts\Validation\ValidatesWhenResolved' => array( 'Closure Object 关联 Illuminate\Validation\ValidationServiceProvider Object', ), ); } } class Application{ protected $serviceProviders = []; //存放服务供应实例 protected $loadedProviders = []; //标记哪些服务供应实例已加载或者说已放入$serviceProviders public function initServiceProviders() { $this->serviceProviders = array( 'Illuminate\Events\EventServiceProvider Object', 'Illuminate\Routing\RoutingServiceProvider Object', 'Illuminate\Auth\AuthServiceProvider Object', 'Illuminate\Routing\ControllerServiceProvider Object', 'Illuminate\Cookie\CookieServiceProvider Object', 'Illuminate\Database\DatabaseServiceProvider Object', 'Illuminate\Encryption\EncryptionServiceProvider Object', 'Illuminate\Filesystem\FilesystemServiceProvider Object', //FoundationServiceProvider extends AggregateServiceProvider register添加进来,并没有绑定bindings,而是放在了FoundationServiceProvider->instances中 'Illuminate\Foundation\Providers\FormRequestServiceProvider Object', 'Illuminate\Session\SessionServiceProvider Object', 'Illuminate\Validation\ValidationServiceProvider Object', 'Illuminate\View\ViewServiceProvider Object', //以下4个只是添加到serviceProviders中,具体注册什么回调是留给用户自定义的 'App\Providers\AppServiceProvider Object', 'App\Providers\AuthServiceProvider Object', 'App\Providers\EventServiceProvider Object', 'App\Providers\RouteServiceProvider Object', ); } public function initLoadedProviders() { $this->loadedProviders = array( 'Illuminate\Events\EventServiceProvider' => true, 'Illuminate\Routing\RoutingServiceProvider' => true, 'Illuminate\Auth\AuthServiceProvider' => true, 'Illuminate\Routing\ControllerServiceProvider' => true, 'Illuminate\Cookie\CookieServiceProvider' => true, 'Illuminate\Database\DatabaseServiceProvider' => true, 'Illuminate\Encryption\EncryptionServiceProvider' => true, 'Illuminate\Filesystem\FilesystemServiceProvider' => true, 'Illuminate\Foundation\Providers\FormRequestServiceProvider' => true, 'Illuminate\Session\SessionServiceProvider' => true, 'Illuminate\Validation\ValidationServiceProvider' => true, 'Illuminate\View\ViewServiceProvider' => true, 'App\Providers\AppServiceProvider' => true, 'App\Providers\AppServiceProvider' => true, 'App\Providers\AuthServiceProvider' => true, 'App\Providers\EventServiceProvider' => true, 'App\Providers\RouteServiceProvider' => true, ); } } class Request { //Symfony\Component\HttpFoundation\Request /** * @param array $query The GET parameters * @param array $request The POST parameters * @param array $attributes The request attributes (parameters parsed from the PATH_INFO, ...) * @param array $cookies The COOKIE parameters * @param array $files The FILES parameters * @param array $server The SERVER parameters * @param string|resource $content The raw body data */ public function initialize(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null) { $this->request = new ParameterBag($request); $this->query = new ParameterBag($query); $this->attributes = new ParameterBag($attributes); $this->cookies = new ParameterBag($cookies); $this->files = new FileBag($files); $this->server = new ServerBag($server); $this->headers = new HeaderBag($this->server->getHeaders()); $this->content = $content; $this->languages = null; $this->charsets = null; $this->encodings = null; $this->acceptableContentTypes = null; $this->pathInfo = null; $this->requestUri = null; $this->baseUrl = null; $this->basePath = null; $this->method = null; $this->format = null; } } |