xiaohuilam / laravel

Laravel 深入详解 —— 源代码解析,新手进阶指南

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

08. SessionServiceProvider 详解

xiaohuilam opened this issue · comments

前言还没想好。

服务提供者部分

SessionServiceProvider 没有 boot 方法,其 register 方法为

public function register()
{
$this->registerSessionManager();
$this->registerSessionDriver();
$this->app->singleton(StartSession::class);
}

作用

下面,我们以 SESSION_DRIVER=file 继续分析
SESSION_DRIVERfile 时,会调用到 createFileDriver

protected function createFileDriver()
{
return $this->createNativeDriver();
}

createFileDriver 调用了 createNativeDriver
protected function createNativeDriver()
{
$lifetime = $this->app['config']['session.lifetime'];
return $this->buildSession(new FileSessionHandler(
$this->app['files'], $this->app['config']['session.files'], $lifetime
));
}

这里 $this->app['config']['session.files'] 得到的是

'files' => storage_path('framework/sessions'),

然后通过此处实例化 Illuminate\Session\FileSessionHandler

return $this->buildSession(new FileSessionHandler(

然后调用 buildSession 获得 \Illuminate\Session\Store 对象

protected function buildSession($handler)
{
if ($this->app['config']['session.encrypt']) {
return $this->buildEncryptedSession($handler);
}
return new Store($this->app['config']['session.cookie'], $handler);
}

session 功能 / 操作部分

读取 session

当触发 Session::start 时,

public function start()
{
$this->loadSession();
if (! $this->has('_token')) {
$this->regenerateToken();
}
return $this->started = true;
}

调用的 loadSession

protected function loadSession()
{
$this->attributes = array_merge($this->attributes, $this->readFromHandler());
}

调用的 readFromHandler

protected function readFromHandler()
{
if ($data = $this->handler->read($this->getId())) {
$data = @unserialize($this->prepareForUnserialize($data));
if ($data !== false && ! is_null($data) && is_array($data)) {
return $data;
}
}
return [];
}

这里的 read 方法,就是 FileSessionHandler::read

public function read($sessionId)
{
if ($this->files->isFile($path = $this->path.'/'.$sessionId)) {
if ($this->files->lastModified($path) >= Carbon::now()->subMinutes($this->minutes)->getTimestamp()) {
return $this->files->sharedGet($path);
}
}
return '';
}

执行到这里时, session 中的数据就被存放到了 Illuminate\Session\Store::$attributes 了。

而执行 Session::get 时,

public function get($key, $default = null)
{
return Arr::get($this->attributes, $key, $default);
}

正好就能从 Store::$attributes 中取出 session 的数据了。

写入 session

当我们使用 Illuminate\Support\Facades\Session 时,操作是调用到的 session,也就是 Illuminate\Session\SessionManager。但是在 Illuminate\Support\Manager__call 魔术方法,实现了将 session.driver 载入到 session 中被执行的能力。

public function __call($method, $parameters)
{
return $this->driver()->$method(...$parameters);
}

有兴趣的同学请阅读 15. Laravel 神奇的 Manager 类

假如我们执行 Session::put('key', 'value')
会穿透到

public function put($key, $value = null)
{
if (! is_array($key)) {
$key = [$key => $value];
}
foreach ($key as $arrayKey => $arrayValue) {
Arr::set($this->attributes, $arrayKey, $arrayValue);
}
}

当我们手动 Session::save 时,或者程序终止运行触发 register_shutdown_function 时,会触发

public function save()
{
$this->ageFlashData();
$this->handler->write($this->getId(), $this->prepareForStorage(
serialize($this->attributes)
));
$this->started = false;
}

也就是 FileSessionHandler::write

public function write($sessionId, $data)
{
$this->files->put($this->path.'/'.$sessionId, $data, true);
return true;
}

至此,写入 session 的流程走完。