支付宝扫一扫付款
微信扫一扫付款
(微信为保护隐私,不显示你的昵称)
Symfony的HttpFoundation组件有一个强力而灵活的session子系统,它被设计为通过一个“使用了多样化的session storage驱动”的简单面向对象接口来进行session管理。
Session的使用,靠的是实现了SessionInterface
接口的Session
类。
确保你的PHP原生session在使用Session类之前没有被启动。如果你的遗产级程序中的session系统启动了原生session,参考整合传统Session。
快速示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | use Symfony\Component\HttpFoundation\Session\Session;
$session = new Session();
$session->start();
// set and get session attributes 设置和取得属性
$session->set('name', 'Drak');
$session->get('name');
// set flash messages 设置flash信息(提示条子)
$session->getFlashBag()->add('notice', 'Profile updated');
// retrieve messages 取出flash信息
foreach ($session->getFlashBag()->get('notice', array()) as $message) {
echo '<div class="flash-notice">'.$message.'</div>';
} |
Symfony的session在设计上是用来取代若干原生的PHP函数的。在程序中应该避免使用session_start()
、session_regenerate_id()
、session_id()
、session_name
和session_destroy()
等等,而使用下文中提到的API来替代之。
虽然显式地启动一个session是被推荐的,但session确实可以随需启动,也就是说,任何一个含有session的请求都可以对session数据进行读写。(译注:session在Symfony里是随取随用毋需特殊步骤的)。
Symfony的session与php.ini
中的session.auto_start = 1
是不兼容的。这个指令应该在php.ini
中关掉,或者在服务器的指令(directive)中乃至.htaccess
文件中关掉。
Session
类实现SessionInterface
接口。
Session
类有下面罗列的简单API,被归为三组:
start()
session_start()
。migrate()
session_regenerate_id()
。本方法可选地(optionally)用于改变新cookie的lifetime(生命周期),调用这个方法时,cookie将被发出(emitted)。invalidate()
session_destroy()
。getId()
session_id()
。setId()
session_id()
。getName()
session_name()
。setName()
session_name()
。set()
get()
all()
has()
replace()
remove()
clear()
这些属性,在内部被存放于一个“包(Bag)”中,Bag是个对象,但操作起来和数组类似。有一些方法专门用于“Bag”的管理:
registerBag()
SessionBagInterface
接口(的实例)。getBag()
SessionBagInterface
接口(的实例)。getFlashBag()
FlashBagInterface
接口(的实例)。这只是getBag()
的一个快捷方法。getMetadataBag()
MetadataBag
,内含sesion相关信息。PHP的session管理需要使用$_SESSION
超全局变量,但这在OOP程序中会干扰代码的可测试性以及封装。为了克服这种问题,Symfony使用了连接了session的session bag 来封装一组特定属性集或flash messages。
这种方法同时削弱了$_SESSION
超全局变量中的命名空间污染(namespace pollution),这是因为每个bag把它所有的数据存放在一个独立的命名空间之下。这让Symfony能够与其他程序或类库“和平共处”,它们可能使用了$_SESSION
超全局变量,但其所有数据都能与Symfony的session管理兼容。
Symfony提供了两种storage bags,分属两种不同的实现方法。因为是对应接口,所以在必要时,你可以扩展它们,或创建自己的bag类型。
SessionBagInterface
有下列API,主要是为了满足内部使用:
getStorageKey()
$_SESSION
下面数组的键。这个值基本上可以保持其默认值作内部使用。initialize()
getName()
属性包实现AttributeBagInterface
接口的目的是要操作session属性的存储。这可能包括像是用户ID,以及“记住我”的登陆设置,或是其他基于用户状态的信息这一类东东。
AttributeBag
NamespacedAttributeBag
因为每个键必须唯一,任何扁平的“键-值”存储系统都被局限在“对于复杂数据”的扩展性上。你可以对每个键引入命名约定来实现命名空间,以便你程序的不同部分能够互相操作而无有冲突。例如,module.foo
和module2.foo
。但是,当属性是数组时,这种方式不很便于实践,例如,对于一组tokens。这时,管理数组变成了负担,因为你不得不取出数组然后处理它,最后再存回去:
因此任何类似处理都可能很快变为难堪,甚至向数组中再添加一个token这种简单的动作也是如此:
1 2 3 | $tokens = $session->get('tokens');
$tokens['c'] = $value;
$session->set('tokens', $tokens); |
使用结构化命名空间,像下面这样使用一个namespace character(命名空间符号,默认是/
),键可以被转换成数组结构:
1 | $session->set('tokens/c', $value); |
通过这种方式,你可以直接而轻松地访问到“属性数组”中的键。
AttributeBagInterface
接口有以下简单API:
set()
get()
all()
has()
replace()
remove()
clear()
FlashBagInterface
接口的目的是要提供一种方式来设置和取出“基于当前session基本内容”中的信息。通常,它的工作流是在一次请求中设置flash messages,然后在页面跳转之后再显示这些(一般用作提示的)信息。比如,用户提交的表单触发了控制器的更新动作,处理完(表单数据)之后,控制器要跳转页面到“已更新的页面”或是“一个错误页”。Flash messages是在上一个页面请求中被设置(在session中)的,将被立即显示在下一个“已经加载了session”的页面中。这是仅用于flash messages的一个程序(接口)。
AutoExpireFlashBag
FlashBag
FlashBagInterface
有如下简单API:
add()
set()
string
array(数组)方式取出。get()
setAll()
type => array(messages)
。all()
peek()
peekAll()
has()
keys()
clear()
对于简单的程序,每个类型有一条flash信息足够了,例如,表单提交之后的确认信息。但是,flash信息被存入的是一个键化数组——flash的$type
就是键——这表示你的程序可以对某给定类型提供多条信息。这让本API能够用在你程序中的复杂信息场景中:
1 2 3 4 5 6 7 8 9 10 11 12 | use Symfony\Component\HttpFoundation\Session\Session;
$session = new Session();
$session->start();
// add flash messages 添加flash信息
$session->getFlashBag()->add(
'warning',
'Your config file is writable, it should be set read-only'
);
$session->getFlashBag()->add('error', 'Failed to update name');
$session->getFlashBag()->add('error', 'Another error'); |
1 2 3 4 5 6 7 8 9 | // display warnings 显示警告
foreach ($session->getFlashBag()->get('warning', array()) as $message) {
echo '<div class="flash-warning">'.$message.'</div>';
}
// display errors 显示错误
foreach ($session->getFlashBag()->get('error', array()) as $message) {
echo '<div class="flash-error">'.$message.'</div>';
} |
1 2 3 4 5 | foreach ($session->getFlashBag()->all() as $type => $messages) {
foreach ($messages as $message) {
echo '<div class="flash-'.$type.'">'.$message.'</div>';
}
} |
本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。