1、初始化Application
// realpath(__DIR__.'/../') 为web应用目录
// 如 D:\www\laravel5.1\
$app = new Illuminate\Foundation\Application(
realpath(__DIR__.'/../')
);
接下来调用 Application类的构造方法
/**
* Create a new Illuminate application instance.
*
* @param string|null $basePath
* @return void
*/
public function __construct($basePath = null)
{
// 注册基本绑定 这一步主要是把app和Illuminate\Container\Container指向Application实例,并添加到instances属性里
$this->registerBaseBindings();
// 注册基本服务提供者,添加到bindings属性里
$this->registerBaseServiceProviders();
// 注册核心类的别名, 添加到aliases属性里
$this->registerCoreContainerAliases();
// 设置根路径,添加到instances属性里
if ($basePath) {
$this->setBasePath($basePath);
}
}
1.1 注册基本绑定
/**
* Register the basic bindings into the container.
*
* @return void
*/
protected function registerBaseBindings()
{
// $this Application实例
static::setInstance($this);
// app指向Illuminate\Foundation\Application实例
$this->instance('app', $this);
// Illuminate\Container\Container指向Illuminate\Foundation\Application实例
$this->instance('Illuminate\Container\Container', $this);
//dd($this->instances);
}
输出$this->instances结果为:
array:2 [▼
"app" => Application {#2 ▶}
"Illuminate\Container\Container" => Application {#2 ▶}
]
1.2 注册基本服务提供者
/**
* Register all of the base service providers.
*
* @return void
*/
protected function registerBaseServiceProviders()
{
// 注册事件服务提供者
$this->register(new EventServiceProvider($this));
// 注册路由服务提供者
$this->register(new RoutingServiceProvider($this));
}
EventServiceProvider 继承 Illuminate\Support\ServiceProvider类,实例化时会先调用ServiceProvider的构造方法
/**
* Create a new service provider instance.
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @return void
*/
public function __construct($app)
{ // 将Application实例赋值给当前对象的成员变量
$this->app = $app;
}
register方法
/**
* Register a service provider with the application.
*
* @param \Illuminate\Support\ServiceProvider|string $provider
* @param array $options
* @param bool $force
* @return \Illuminate\Support\ServiceProvider
*/
public function register($provider, $options = [], $force = false)
{
if ($registered = $this->getProvider($provider) && ! $force) {
return $registered;
}
// If the given "provider" is a string, we will resolve it, passing in the
// application instance automatically for the developer. This is simply
// a more convenient way of specifying your service provider classes.
if (is_string($provider)) {
$provider = $this->resolveProviderClass($provider);
}
// 这里调用的是EventServiceProvider类的register方法
$provider->register();
// Once we have registered the service we will iterate through the options
// and set each of them on the application so they will be available on
// the actual loading of the service objects and for developer usage.
foreach ($options as $key => $value) {
$this[$key] = $value;
}
$this->markAsRegistered($provider);
// If the application has already booted, we will call this boot method on
// the provider class so it has an opportunity to do its boot logic and
// will be ready for any usage by the developer's application logics.
if ($this->booted) {
$this->bootProvider($provider);
}
return $provider;
}
EventServiceProvider类的register方法
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
// 调用Application实例的singleton方法,该方法继承自
// Illuminate\Container\Container.php
$this->app->singleton('events', function ($app) {
return (new Dispatcher($app))->setQueueResolver(function () use ($app) {
return $app->make('Illuminate\Contracts\Queue\Factory');
});
});
}
/**
* Register a shared binding in the container.
*
* @param string|array $abstract
* @param \Closure|string|null $concrete
* @return void
*/
public function singleton($abstract, $concrete = null)
{ // 注册绑定
$this->bind($abstract, $concrete, true);
}
在bind方法中将event添加到 binding中
$this->bindings[$abstract] = compact('concrete', 'shared');
这时输出$this->bindings结果如下
array:1 [▼
"events" => array:2 [▼
"concrete" => Closure {#4 ▶}
"shared" => true
]
]
markAsRegistered方法
/**
* Mark the given provider as registered.
*
* @param \Illuminate\Support\ServiceProvider $provider
* @return void
*/
protected function markAsRegistered($provider)
{
// 这里要特别主要 $this['events'],调用的是数组中不存在的key
$this['events']->fire($class = get_class($provider), [$provider]);
$this->serviceProviders[] = $provider;
$this->loadedProviders[$class] = true;
}
注:因为该类实现了 ArrayAccess接口,当调用数组中不存在的key时,会调用 ArrayAccess::offsetGet 方法(具体自行参考PHP参考文档ArrayAccess),这个方法在Illuminate\Container\Container.php中实现
/**
* Get the value at a given offset.
*
* @param string $key
* @return mixed
*/
public function offsetGet($key)
{
return $this->make($key);
}
接下来的部分是RoutingServiceProvider
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->registerRouter();
$this->registerUrlGenerator();
$this->registerRedirector();
$this->registerPsrRequest();
$this->registerPsrResponse();
$this->registerResponseFactory();
//dd($this->app);
}
这部分的目的主要是绑定关系,从输出结果我们可以明显看出
Application {#2 ▼
#basePath: null
#hasBeenBootstrapped: false
#booted: false
#bootingCallbacks: []
#bootedCallbacks: []
#terminatingCallbacks: []
#serviceProviders: array:1 [▶]
#loadedProviders: array:1 [▶]
#deferredServices: []
#monologConfigurator: null
#databasePath: null
#storagePath: null
#environmentPath: null
#environmentFile: ".env"
#namespace: null
#resolved: array:1 [▶]
#bindings: array:7 [▼
"events" => array:2 [▶]
"router" => array:2 [▶]
"url" => array:2 [▶]
"redirect" => array:2 [▶]
"Psr\Http\Message\ServerRequestInterface" => array:2 [▶]
"Psr\Http\Message\ResponseInterface" => array:2 [▶]
"Illuminate\Contracts\Routing\ResponseFactory" => array:2 [▶]
]
注:在调用registerRouter方法时,也就是下面这段代码
/**
* Register the router instance.
*
* @return void
*/
protected function registerRouter()
{
// 这里是一个赋值操作,因为实现了ArrayAccess接口,如果$this->app['router']不存在,则会调用ArrayAccess::offsetSet方法,也就是(Illuminate\Container\Container.php里的offsetSet方法)。
$this->app['router'] = $this->app->share(function ($app) {
return new Router($app['events'], $app);
});
}
1.3 注册核心类别名
通过输出$this->app得到以下结果,在aliases数组中可以看到对应关系
Application {#2 ▼
#basePath: null
#hasBeenBootstrapped: false
#booted: false
#bootingCallbacks: []
#bootedCallbacks: []
#terminatingCallbacks: []
#serviceProviders: array:2 [▶]
#loadedProviders: array:2 [▶]
#deferredServices: []
#monologConfigurator: null
#databasePath: null
#storagePath: null
#environmentPath: null
#environmentFile: ".env"
#namespace: null
#resolved: array:1 [▶]
#bindings: array:7 [▶]
#instances: array:3 [▶]
#aliases: array:59 [▼
"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"
]
1.4 设置根路径
#instances: array:10 [▼
"app" => Application {#2}
"Illuminate\Container\Container" => Application {#2}
"events" => Dispatcher {#5 ▶}
"path" => "D:\www\laravel5.1\app"
"path.base" => "D:\www\laravel5.1"
"path.config" => "D:\www\laravel5.1\config"
"path.database" => "D:\www\laravel5.1\database"
"path.lang" => "D:\www\laravel5.1\resources\lang"
"path.public" => "D:\www\laravel5.1\public"
"path.storage" => "D:\www\laravel5.1\storage"
]
2、注册共享的Kernel和异常处理器
$app->singleton(
Illuminate\Contracts\Http\Kernel::class,
App\Http\Kernel::class
);
$app->singleton(
Illuminate\Contracts\Console\Kernel::class,
App\Console\Kernel::class
);
$app->singleton(
Illuminate\Contracts\Debug\ExceptionHandler::class,
App\Exceptions\Handler::class
);
上述代码将绑定关系添加到bindings属性里,里面的::class 是php新增的静态属性
#bindings: array:10 [▼
"events" => array:2 [▶]
"router" => array:2 [▶]
"url" => array:2 [▶]
"redirect" => array:2 [▶]
"Psr\Http\Message\ServerRequestInterface" => array:2 [▶]
"Psr\Http\Message\ResponseInterface" => array:2 [▶]
"Illuminate\Contracts\Routing\ResponseFactory" => array:2 [▶]
"Illuminate\Contracts\Http\Kernel" => array:2 [▶]
"Illuminate\Contracts\Console\Kernel" => array:2 [▶]
"Illuminate\Contracts\Debug\ExceptionHandler" => array:2 [▶]
]
3、处理请求和响应
这时我们获取$app后返回index.php页面,然后执行
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
这里要注意,make方法调用的是子类Illuminate\Foundation\Application.php里的方法,然后在调用父类Illuminate\Container\Container.php的make方法
接着是make方法里的
// 这里返回bindings数组里的数据,因为我们在获取$app的时候已经把
// "Illuminate\Contracts\Http\Kernel"绑定了
$concrete = $this->getConcrete($abstract);
接着我们调用$object = $this->build($concrete, $parameters);
这build方法中
if ($concrete instanceof Closure) {
return $concrete($this, $parameters);
}
因为$concrete是闭包,所以直接返回,这里调用的是我们绑定在app里的闭包也就是,
“Illuminate\Contracts\Http\Kernel” => array:2 [▼
“concrete” => Closure {#23 ▼
class: “Illuminate\Container\Container”
this: Application {#2}
parameters: array:2 [▶]
use: array:2 [▼
“$abstract” => “Illuminate\Contracts\Http\Kernel”
“$concrete” => “App\Http\Kernel”
]
file: “D:\www\laravel5.1\vendor\laravel\framework\src\Illuminate\Container\Container.php”
line: “222 to 226”
}
“shared” => true
]
执行这个方法 concrete( this, $parameters)的时候也就是调用Illuminate\Container\Container.php第222到226行之间的代码,传递的参数就是上述use中黑色斜线部分标注的,
function ($c, $parameters = []) use ($abstract, $concrete) {
// 根据上述use中的参数,这里赋值应该是make
$method = ($abstract == $concrete) ? 'build' : 'make';
// 然后在调用application.php中的make方法,$concrete对应的就是App\Http\Kernel
return $c->$method($concrete, $parameters);
}
最终是调用构造函数设置 app/ router,初始化$router中middleware数值(定义在D:\www\laravel5.1\app\Http\Kernel.php文件中,这里我们可以添加任何自定义中间件)实例化App\Http\Kernel
Kernel {#24 ▼
#middleware: array:6 [▼
0 => "Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode"
1 => "App\Http\Middleware\EncryptCookies"
2 => "Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse"
3 => "Illuminate\Session\Middleware\StartSession"
4 => "Illuminate\View\Middleware\ShareErrorsFromSession"
5 => "App\Http\Middleware\VerifyCsrfToken"
]
#routeMiddleware: array:4 [▼
"auth" => "App\Http\Middleware\Authenticate"
"auth.basic" => "Illuminate\Auth\Middleware\AuthenticateWithBasicAuth"
"guest" => "App\Http\Middleware\RedirectIfAuthenticated"
"test" => "App\Http\Middleware\TestMiddleware"
]
#app: Application {#2 ▶}
#router: Router {#88 ▶}
#bootstrappers: array:7 [▶]
}
接下来是处理web请求的核心部分 handle方法
$response = $kernel->handle(
// $request是经过Symfony封装的请求对象
$request = Illuminate\Http\Request::capture()
);
调用bootstrap方法,启动一系列启动类的bootstrap(定义在\Illuminate\Foundation\Http\Kernel.php中)方法:
protected $bootstrappers = [
// 该类用来读取.env定义的变量 环境配置($app[‘env’])
'Illuminate\Foundation\Bootstrap\DetectEnvironment',
// 扫描config文件下的所有.php结尾的配置文件 基本配置($app[‘config’])
'Illuminate\Foundation\Bootstrap\LoadConfiguration',
// 日志文件($app[‘log’])
'Illuminate\Foundation\Bootstrap\ConfigureLogging',
// 错误&异常处理
'Illuminate\Foundation\Bootstrap\HandleExceptions',
//清除已解析的Facade并重新启动,注册config文件中alias定义的所有Facade类到容器 (定义在配置文件app.php中的aliases数组)
'Illuminate\Foundation\Bootstrap\RegisterFacades',
//注册config中providers定义的所有Providers类到容器 (定义在配置文件app.php中的providers数组)
'Illuminate\Foundation\Bootstrap\RegisterProviders',
//调用所有已注册Providers的boot方法
'Illuminate\Foundation\Bootstrap\BootProviders',
];
通过Pipeline发送请求,经过中间件,再由路由转发,最终返回响应
new Pipeline($this->app))
->send($request)
->through($this->middleware)
->then($this->dispatchToRouter()
将响应信息发送到浏览器:
$response->send();
处理继承自TerminableMiddleware接口的中间件(Session)并结束应用生命周期:
$kernel->terminate($request, $response);