PHP-php如何序列化/存储闭包(Closure)

小组事务管理 小组事务管理 主题:974 回复:1955

PHP-php如何序列化/存储闭包(Closure)

虐人心 发布于 2017-07-19 字数 1186 浏览 1401 回复 4

在最新的Zend Framework 2.0中,已经开始大量采用php5.3的闭包特性。可以通过在配置文件中引入闭包来初始化模块。(参看:http://packages.zendframework.com/docs/latest/manual/en/modules/zend.service-manager.quick-start.html)

但是配置文件会存在缓存,格式转换等需求(php => xml),此时对于配置文件内的闭包应该如何处理? 直接序列化闭包php并不支持。

补充,换php5.4测试了一下,php5.4只是能支持类与对象,但对于闭包还是没有办法,下面是一个ZF2的配置文件例子,里面包含了从配置文件初始化数据库连接服务。一旦序列化就会报错

Fatal error: Uncaught exception 'Exception' with message 'Serialization of 'Closure' is not allowed'

$config = array(
'service_manager' => array(
'factories' => array(
'ZendDbAdapterAdapter' => function ($sm) {
$config = $sm->get('Configuration');
if(!isset($config['db'])){
return array();
}
$adapter = new ZendDbAdapterAdapter($config['db']);
return $adapter;
},
),
),
);
serialize($config);

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

支持 Markdown 语法,需要帮助?

评论(4

偏爱自由 2017-09-19 4 楼

ZF对配置文件的处理一般是这样的流程:
1、从config.ini/config.php/config.xml文件中读取到配置数据,这里是根据配置文件的类型选择不同的读取插件,比如:
ZendConfigReaderIni
ZendConfigReaderXml
ZendConfigReaderJson
ZendConfigReaderYaml

2、把读取的数据,统一转换为数组形式然后存储到缓存中
3、具体到功能模块,从缓存中加载配置信息,而不是重新解析配置文件。

可以研究一下ZF的My_Application类:

 class My_Application extends Zend_Application
{
/**

  • @var Zend_Cache_Core|null
    */
    protected $_configCache;
public function __construct($environment, $options = null, Zend_Cache_Core $configCache = null)
{
    $this->_configCache = $configCache;
    parent::__construct($environment, $options);
}

protected function _cacheId($file)
{
    return md5($file . '_' . $this->getEnvironment());
}

//Override
protected function _loadConfig($file)
{
    $suffix = strtolower(pathinfo($file, PATHINFO_EXTENSION));
    if (
        $this->_configCache === null 
        || $suffix == 'php' 
        || $suffix == 'inc'
    ) { //No need for caching those
        return parent::_loadConfig($file);
    }

    $configMTime = filemtime($file);

    $cacheId = $this->_cacheId($file);
    $cacheLastMTime = $this->_configCache->test($cacheId);

    if (
        $cacheLastMTime !== false 
        && $configMTime < $cacheLastMTime
    ) { //Valid cache?
        return $this->_configCache->load($cacheId, true);
    } else {
        $config = parent::_loadConfig($file);
        $this->_configCache->save($config, $cacheId, array(), null);

        return $config;
    }
}

}

ZF2改动还是挺大的,光配置文件就可以兼容ini、闭包、xml、json等格式,每个格式都对应的处理插件:
读取:

ZendConfigReaderIni
ZendConfigReaderXml
ZendConfigReaderJson
ZendConfigReaderYaml
编辑:

ZendConfigWriterIni
ZendConfigWriterXml
ZendConfigWriterPhpArray
ZendConfigWriterJson
ZendConfigWriterYaml

参考一下手册:
zend.config

偏爱自由 2017-09-11 3 楼

zf2.0的模块配置是指module里面getConfig获取的内容,其他配置是运行时加载到各个service manager里面的。getConfig获取的内容都是数组,并不存在匿名函数。而能缓存的也只是这些数组,所以不存在这个问题。

甜柠檬 2017-09-05 2 楼

zf1.x中的配置文件缓存的其实就是被解析后的zend_config对象序列化字符串,当然也可以toArray后缓存数组。

如果拿这个思路来说的话,那其实zf2以后你为了提高性能,应该也是缓存解析完配置文件后生成的那个对象,应该是已经可以序列化了,因为闭包的那个属性已经被初始化了吧?

如果是zf2.0官方的那个例子,那已经是php的数组了,不需要缓存了,你只需要include进来就行了,这已经是最优化了,你还能如何优化?

看这里:
http://www.codingcool.com/?p=268

瑾兮 2017-08-25 1 楼

我只能想到把代码写在字符串里面,然后和所有用到的变量一起存起来,不过这个不算序列化吧……

$closure = {'code'=>'function() use($var1,$var2){...}','uses'=>{'var1'=>1,'var2'=>2}};
$serialized = json_encode($closure);

$closure = json_decode($serialized,true);
for($closure['uses'] as $k=>$v)
{
$($k) = $v;
}
$func = eval($closure['code']);