共计 1566 个字符,预计需要花费 4 分钟才能阅读完成。
前言
提高页面速度的一个很好用的方法就是使用 Cache
。而在 Laravel 中 Cache 的使用和配置也是相当方便,在项目中合理的使用能得到意想不到的效果(当然,使用不当也会造成坏的效果)。
遇见问题
于是,我写下了下面看似非常正常的代码:
$newsList = Cache::remember('newsList'.$uuid, $minutes, function() {
return News::with('lastReplyUser', 'user')
->checked()
->recentReply()
->paginate(Config::get('page.newsListSize'));
});
刷新页面后的结果让我出乎意料,报错Exception Serialization of 'Closure' is not allowed
。
分析问题
速速打开 xdebug 调试,明明返回的是 Paginator 这个对象。怎么会说无法序列化 Closure 呢?
正如错误提示,这个 paginator 对象有属性是闭包,所以在序列化的时候无法进行。
在强有力的 xdebug 的帮助下,我找到了元凶。
具体赋值位置:/Path/To/Nidexiangmu/vendor/laravel/framework/src/Illuminate/View/Engines/EngineResolver.php 30 行这个方法的行为
public function register($engine, Closure $resolver)
{
$this->resolvers[$engine] = $resolver;
}
解决问题
随随便便修改框架源代码,这不是咱能干的事儿。既然这样,那就来个曲线救国吧!对 paginator 无法缓存,咱们就缓存点别的。
方案 1
对查询进行缓存
$newsList = News::with('lastReplyUser', 'user')
->checked()
->whereNotIn('id', $selectedId)
->recentReply()
->remember($minutes) # 注意这一行
->paginate(Config::get('page.newsListSize'));
方案 2
对 paginator 需要用到的内容 (items 和链接) 进行缓存
$newsList = Cache::remember('newsList'.$uuid, $minutes, function() {
$data = News::with('lastReplyUser', 'user')
->checked()
->recentReply()
->paginate(Config::get('page.newsListSize'));
return ['result' => $data->getItems(), 'links' => (string)$data->links()];
});
总结
注意,方案 2 中的 *links()
* 这个方法调用后使用了 string 的强制转换,因为返回的内容是 view
对象,而 view 对象的属性中有闭包,所以任何时候不要试图序列化(包括缓存操作这种包含序列号的操作)view 对象和属性中拥有 view 对象的数组或对象(这句话好拗口啊,其实就是只有存在 view 对象,就不要序列化或缓存)。
Ubuntu 下使用 Nginx 部署 Laravel http://www.linuxidc.com/Linux/2015-08/121988.htm
Ubuntu 14.04 上使用 Nginx 部署 Laravel 5.0 http://www.linuxidc.com/Linux/2015-08/121986.htm
本文永久更新链接地址:http://www.linuxidc.com/Linux/2015-11/124751.htm