不要开启 php redis 扩展的自动序列化选项
php redis 扩展有自动序列化选项,在存储kv数据的时候,可以少写点代码就打开了,使用的过程中忽然发现了一个令人郁闷的地方。
扩展没有对你要存储的值做类型判断,任何类型的值都做了自动序列化,比如下面这段代码
$rd = new Redis(); $r = $rd->connect( '127.0.0.1', 6379, 1 ); $rd->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP); $rd->set('k', 1); var_dump($rd->incr('k')); echo $rd->getLastError(), PHP_EOL; echo $rd->get('k');
你存储了一个int进去,然后在incr,就会失败
bool(false) ERR value is not an integer or out of range 1
直接用redis-cli去看下,发现,value 被序列化了
127.0.0.1:6379> get k "i:1;"
这是php redis 扩展序列化的部分代码(在源码包的library.c),你会发现,这个序列化并没有像memcached扩展一样做类型判断,而是全部序列化。
PHP_REDIS_API int redis_serialize(RedisSock *redis_sock, zval *z, char **val, strlen_t *val_len TSRMLS_DC) { …… switch(redis_sock->serializer) { case REDIS_SERIALIZER_NONE: …… case REDIS_SERIALIZER_PHP: #if ZEND_MODULE_API_NO >= 20100000 PHP_VAR_SERIALIZE_INIT(ht); #else zend_hash_init(&ht, 10, NULL, NULL, 0); #endif php_var_serialize(&sstr, z, &ht); #if (PHP_MAJOR_VERSION < 7) *val = estrndup(sstr.c, sstr.len); *val_len = sstr.len; #else *val = estrndup(ZSTR_VAL(sstr.s), ZSTR_LEN(sstr.s)); *val_len = ZSTR_LEN(sstr.s); #endif smart_str_free(&sstr); #if ZEND_MODULE_API_NO >= 20100000 PHP_VAR_SERIALIZE_DESTROY(ht); #else zend_hash_destroy(&ht); #endif return 1; case REDIS_SERIALIZER_IGBINARY: …… } return 0; }
看来php redis 这扩展出来这么久,用户量这么大,但是文档都没进到php官方文档,也不是没有原因的。
更多架构、PHP、GO相关踩坑实践技巧请关注我的公众号:PHP架构师
原文地址:https://my.oschina.net/u/222608/blog/1925135