在 app.php
下,使用 providers
的这个类:
Illuminate\Session\SessionServiceProvider::class,
点开,看到 register()
方法:
public function register()
{
$this->registerSessionManager();
$this->registerSessionDriver();
$this->app->singleton('Illuminate\Session\Middleware\StartSession');
}
也就是最后使用到的是:Illuminate\Session\Middleware\StartSession
,这个类中有个 handle()
方法:
public function handle($request, Closure $next)
{
$this->sessionHandled = true;
// If a session driver has been configured, we will need to start the session here
// so that the data is ready for an application. Note that the Laravel sessions
// do not make use of PHP "native" sessions in any way since they are crappy.
if ($this->sessionConfigured()) {
$session = $this->startSession($request);
$request->setSession($session);
}
$response = $next($request);
// Again, if the session has been configured we will need to close out the session
// so that the attributes may be persisted to some storage medium. We will also
// add the session identifier cookie to the application response headers now.
if ($this->sessionConfigured()) {
$this->storeCurrentUrl($request, $session);
$this->collectGarbage($session);
$this->addCookieToResponse($response, $session);
}
return $response;
}
这里就是一个 middleware
的设计思想,在其中的$this->startSession
中获取Session的方法是getSession()
:
$session = $this->manager->driver();
这里面的$this->manager
通过依赖注入,注入的类是Illuminate\Session\SessionManager
,也就是在这里调用了SessionManager
的 driver()
方法。而 driver()
方法位于 SessionManager
的父类 Manager
中,具体是这个样子的:
public function driver($driver = null)
{
$driver = $driver ?: $this->getDefaultDriver();
// If the given driver has not been created before, we will create the instances
// here and cache it so we can return it next time very quickly. If there is
// already a driver created by this name, we'll just return that instance.
if (! isset($this->drivers[$driver])) {
$this->drivers[$driver] = $this->createDriver($driver);
}
return $this->drivers[$driver];
}
在这里调用 getDefaultDriver()
方法,又回到了Illuminate\Session\SessionManager
类中,代码如下:
public function getDefaultDriver()
{
return $this->app['config']['session.driver'];
}
到这里就很清晰咯,就是我们在 app/config/session.php
中定义的driver
配置项,获取这个配置后,我们可以从 createDriver()
的源码看到,它实际上是调用 createXXXXDriver()
的方式获取到driver的。。
protected function createDriver($driver)
{
$method = 'create'.Str::studly($driver).'Driver';
// We'll check to see if a creator method exists for the given driver. If not we
// will check for a custom driver creator, which allows developers to create
// drivers using their own customized driver creator Closure to create it.
if (isset($this->customCreators[$driver])) {
return $this->callCustomCreator($driver);
} elseif (method_exists($this, $method)) {
return $this->$method();
}
throw new InvalidArgumentException("Driver [$driver] not supported.");
}
比如你配置 app/config/session.php
为 file,也就是 createFileDriver()
。有了 driver 之后,最后通过 buildSession()
创建 session
protected function buildSession($handler)
{
if ($this->app['config']['session.encrypt']) {
return new EncryptedStore(
$this->app['config']['session.cookie'], $handler, $this->app['encrypter']
);
} else {
return new Store($this->app['config']['session.cookie'], $handler);
}
}
然后回到 StartSession
这个类,我们再看 getSession()
这个方法:
$session->setId($request->cookies->get($session->getName()));
这里就根据 cookies
来设置不同的 session
的 key
。这里就创建完 session
了,如何获取 session
的数据呢?依然是在 StartSession
类的 startSession()
方法这里有一句:
$session->start();
点开,看看源码,这个源码位于 Illuminate\Session\Store
中,可以从上面 的 buildSession()
的 new EncryptedStore()
追踪
public function start()
{
$this->loadSession();
if (! $this->has('_token')) {
$this->regenerateToken();
}
return $this->started = true;
}
这里执行下面的 $this->loadSession()
:
protected function loadSession()
{
$this->attributes = array_merge($this->attributes, $this->readFromHandler());
foreach (array_merge($this->bags, [$this->metaBag]) as $bag) {
$this->initializeLocalBag($bag);
$bag->initialize($this->bagData[$bag->getStorageKey()]);
}
}
loadSession()
又执行下面的 $this->readFromHandler()
protected function readFromHandler()
{
$data = $this->handler->read($this->getId());
if ($data) {
$data = @unserialize($this->prepareForUnserialize($data));
if ($data !== false && $data !== null && is_array($data)) {
return $data;
}
}
return [];
}
从 handler
中调用了 read()
方法,这里的 handler 是一个接口 SessionHandlerInterface $handler
,也就是我们预先定义的各种 handler
中读取数据,比如说 app/config/session.php
为 file
就是 FileSessionHandler
,这里就有 read()
方法:
public function read($sessionId)
{
if ($this->files->exists($path = $this->path.'/'.$sessionId)) {
if (filemtime($path) >= Carbon::now()->subMinutes($this->minutes)->getTimestamp()) {
return $this->files->get($path);
}
}
return '';
}
到这里,流程就OK了。