摘要:我们在这个类中的方法看到如下代码,一个典型的过滤器,在这个中获取的方法是。,整个初始化的过程总结下巧妙的使用了面向对象的接口方式,为我们提供了各种各样不同的存储方式,一旦我们了解了存储方式和加密规则,让不同的容器进行共享的目的也可以达到
前些天,为了解答一个问题,就去研究了Laravel的源码,讲讲我的收获:
这个是问题源:
http://segmentfault.com/q/1010000003776645?_ea=365137
本文讲的Laravel全部使用5.1版本。
我们首先看Laravel是如何创建Session组件的。
首先我们可以看见在Kernel.php中注册了StartSession这个类(这里不去讨论Laravel的DI和IoC),看下这个类是如何使用的。
我们在这个类中的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; }
OK,一个典型的过滤器,在这个StartSession中获取Session的方法是getSession。
Get Session它使用了Laravel注入的SessionManager 这个类的完整限定名是:IlluminateSessionSessionManager
/** * Start the session for the given request. * * @param IlluminateHttpRequest $request * @return IlluminateSessionSessionInterface */ protected function startSession(Request $request) { with($session = $this->getSession($request))->setRequestOnHandler($request); $session->start(); return $session; } /** * Get the session implementation from the manager. * * @param IlluminateHttpRequest $request * @return IlluminateSessionSessionInterface */ public function getSession(Request $request) { $session = $this->manager->driver(); $session->setId($request->cookies->get($session->getName())); return $session; }
我们在这个函数中看到,它调用了SessionManager的drive方法,drive方法是SessionManager的父类Manager中定义的,看到它的实现是这样的
/** * Get a driver instance. * * @param string $driver * @return mixed */ 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]; } /** * Create a new driver instance. * * @param string $driver * @return mixed * * @throws InvalidArgumentException */ protected function createDriver($driver) { $method = "create".ucfirst($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."); }
也就是调用getDefaultDriver方法
/** * Get the default session driver name. * * @return string */ public function getDefaultDriver() { return $this->app["config"]["session.driver"]; }
这里就是我们在app/config/session.php中定义的driver字段,获取这个字段后,我们可以从createDriver的源码看到,它实际上是调用createXXXXDriver的方式获取到driver的。
OK,我们看下最简单的File,也就是createFileDriver
/** * Create an instance of the file session driver. * * @return IlluminateSessionStore */ protected function createFileDriver() { return $this->createNativeDriver(); } /** * Create an instance of the file session driver. * * @return IlluminateSessionStore */ protected function createNativeDriver() { $path = $this->app["config"]["session.files"]; return $this->buildSession(new FileSessionHandler($this->app["files"], $path)); } /** * Build the session instance. * * @param SessionHandlerInterface $handler * @return IlluminateSessionStore */ 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); } }
这个Store就是我们Session的实体了,它的具体读写调用使用抽象的Handler进行,也就是说如果是读文件,就new FileHandler如果是Redis就是new RedisHandler实现read和write即可。
Session ID回到StartSession 这个类,我们再看getSession这个方法
$session->setId($request->cookies->get($session->getName()));
了解Web的人都应该知道,session是根据cookie中存的key来区分不同的会话的,所以sessionId尤为重要,这里我们先不关心Cookie是如何读取,我们知道在这里读取了cookie中存放的SessionId就够了。
接下去看怎么加载数据
Data依然是StartSession这个类,
我们看startSession这个方法,下一句调用的就是$session->start();,这句话是干嘛呢?经过前面的分析,我们知道$session已经是Store对象了,那么它的start方法如下:
public function start() { $this->loadSession(); if (! $this->has("_token")) { $this->regenerateToken(); } return $this->started = true; } /** * Load the session data from the handler. * * @return void */ 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()]); } } /** * Read the session data from the handler. * * @return array */ 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 []; }
依次调用了loadSession和readFromHandler 好,可以看到从handler中调用了read方法,这个方法就是从我们之前定义的各种handler中读取数据了,它是个抽象方法,在子类中具体实现,然后返回给Store(存入到Store中的attributes数组中去了,到此为止,Session的初始化方法都结束了,
public function get($name, $default = null) { return Arr::get($this->attributes, $name, $default); }
这个函数去读取Session中的数据了。
SummaryOK,Session整个初始化的过程总结下:
StartSession#handle -> StartSession#startSession -> StartSession#getSession -> SessionManager#getDefaultDriver -> SessionManager#createXXXHandler -> Store -> Store#setId -> Store#startSession
Laravel巧妙的使用了面向对象的接口方式,为我们提供了各种各样不同的存储方式,一旦我们了解了存储方式和加密规则,让不同的web容器进行Session共享的目的也可以达到~
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/21128.html
摘要:在的配置文件中可以设置,比如这个项目中设置名称为我们可以看到刷新页面,查看,会发现一个名称为的,名字就是我们自定义的。而这种加密方式是每次加密的结果都不同,所以表现为的值每次都发生了变化,而实际上并没有改变。 在 Laravel 的配置文件 config/session.php 中可以设置 Session Cookie Name,比如这个项目中设置名称为sns_session: /* ...
摘要:服务器检查该,以此来辨认用户状态。五下的相关应用应用在中配置如下配置项用于设置存储方式,默认是,即存储在文件中,该文件位于配置项配置的路径,即。配置项用于设置有效期,默认为分钟。配置项用于配置数据是否加密。 一、cookie的由来 当用户访问某网站时,web服务器会将部分信息保存到本地计算机上,当用户再次关顾该网站时,服务器会去查看用户是否登录过该网站,如果登录过,就会将这些记录在...
摘要:组件扩展通常有两种方法向容器中绑定自己的接口实现痛过使用工厂模式实现的类注册自己的扩展。类库管理类以工厂模式实现,负责诸如缓存等驱动的实例化。闭包须要传入继承自和容器的实例化对象。当完成扩展之后要记住中替换成自己的扩展名称。 声明:本文并非博主原创,而是来自对《Laravel 4 From Apprentice to Artisan》阅读的翻译和理解,当然也不是原汁原味的翻译,能保证9...
摘要:简介是一套简介,优雅开发框架,通过简单,高雅,表达式语法开发应用。服务器需要有该目录及所有子目录的写入权限可用于存储应用程序所需的一些文件该目录下包括缓存和编译后的视图文件日志目录测试目录该目录下包含源代码和第三方依赖包环境配置文件。 简介 Laravel是一套简介,优雅PHP Web开发框架(PHP Web Framework), 通过简单,高雅,表达式语法开发Web应用。 特点: ...
摘要:如何实现执行脚本,会从中读取配置项,将生成的唯一值保存文件放到配置项中的保存路径和地点。并通过协议返回响应消息头名值发送给客户端。 1、php如何实现session 执行php脚本,session_start()会从php.ini中读取配置项,将生成的唯一值sessionID保存文件放到配置项中的保存路径和地点。并通过HTTP协议返回响应消息头setCookieCookie名=Cook...
阅读 918·2021-09-07 09:58
阅读 1449·2021-09-07 09:58
阅读 2849·2021-09-04 16:40
阅读 2481·2019-08-30 15:55
阅读 2390·2019-08-30 15:54
阅读 1348·2019-08-30 15:52
阅读 403·2019-08-30 10:49
阅读 2580·2019-08-29 13:21