(工作小记)phpredis Redis::SERIALIZER_IGBINARY 自增字段

最近项目中的统计出现了问题,统计数使用redis的incr 自增。修复数据后使用set xxx value 将新的数据替换老数据 发现set更新后数据又从1开始重新增加 最后发现问题出在 [php]$this->setOption ( \Redis::OPT_SERIALIZER, \Redis::SERIALIZER_IGBINARY );[/php] Redis::SERIALIZER_IGBINARY这个参数 Redis::SERIALIZER_IGBINARY [php] $redis->set("a", 3); $redis->incr("a"); // 1 echo $redis->get("a"); // output 1 [/php] Redis::SERIALIZER_PHP [php] $redis->set("a", 3); $redis->incr("a"); // false echo $redis->get("a"); // output 3 [/php] 解决方案 在保存之前临时将参数改为Redis::SERIALIZER_NONE 取消序列化 最后别忘了把它改回来 参考 https://github.com/phpredis/phpredis/issues/246

PHP里的尾递归及其优化

不同的语言对尾递归的支持都有所不同,编译器的优化也不尽相同。我们之前看了C语言的尾递归,那么在PHP里又是如何的呢?

PHP对尾递归没有优化效果

先来看下实验。 [php] <?php function factorial($n) { if($n == 0) { return 1; } return factorial($n-1) * $n; } var_dump(factorial(100)); ?> [/php] 如果安装了XDebug的话,可能会遇到如下错误: Fatal error: Maximum function nesting level of '100' reached, aborting! 这是XDebug的一个保护机制,可以通过max_nesting_level选项来设置。放开设置的话,程序还是能够正常运行的。 即便代码能正常运行,只要我们不断增大参数,程序迟早会报错: Fatal error:  Allowed memory size of … bytes exhausted 为什么呢?简单点说就是递归造成了栈溢出。按照之前的思路,我们可以试下用尾递归来消除递归对栈的影响,提高程序的效率。 [php] <?php function factorial($n, $acc) { if($n == 0) { return $acc; } return factorial($n-1, $acc * $n); } var_dump(factorial(100, 1)); ?> [/php] XDebug同样报错,并且程序的执行时间并没有明显变化。 Fatal error: Maximum function nesting level of '100' reached, aborting! 事实证明,尾递归在php中是没有任何优化效果的。

PHP如何消除递归

先看看下面的源代码: [php] <?php function factorial($n, $accumulator = 1) { if ($n == 0) { return $accumulator; } return function() use($n, $accumulator) { return factorial($n - 1, $accumulator * $n); }; } function trampoline($callback, $params) { $result = call_user_func_array($callback, $params); while (is_callable($result)) { $result = $result(); } return $result; } var_dump(trampoline('factorial', array(100))); ?> [/php] 现在XDebug不再警报效率问题了。 注意到trampoline()函数没?简单点说就是利用高阶函数消除递归。想更进一步了解 call_user_func_array,可以参看这篇文章:PHP函数补完:call_user_func()与call_user_func_array() 还有很多别的方法可以用来规避递归引起的栈溢出问题,比如说Python中可以通过装饰器和异常来消灭尾调用,让人有一种别有洞天的感觉。

小结

在C中的尾递归优化是gcc编译器做的。一般的线性递归修改成为尾递归最大的优势在于减少了递归调用栈的开销。从php那个例子就明显看出来递归开销对程序的影响。但是并不是所有语言都支持尾递归的,即使支持尾递归的语言也一般是在编译阶段对尾递归进行优化,比如C语言对尾递归的优化。在使用尾递归对代码进行优化的时候,必须先了解这门语言对尾递归的支持。 在PHP里,除非能提升代码可读性,否则没有必要使用递归;迫不得已之时,最好考虑使用Tail Call或Trampoline等技术来规避潜在的栈溢出问题。 原文地址 http://www.nowamagic.net/librarys/veda/detail/2334

Yii2.0 字段验证 日期验证 DateValidator

使用yii验证日期 [php] public function rules() { return [ [array_keys($this->attributeLabels()), 'trim'], [['pop_id', 'start_day', 'end_day'], 'required'], [['pop_id'], 'integer'], [['start_day', 'end_day'], 'date', 'message' => " {attribute} 格式不正确"], ]; } [/php] start_day 为2016-03-24 总是返回不正确  可是默认的验证格式就是Y-m-d 最后发现要这么写才行 真是坑啊 [php] public function rules() { return [ [array_keys($this->attributeLabels()), 'trim'], [['pop_id', 'start_day', 'end_day'], 'required'], [['pop_id'], 'integer'], [['start_day', 'end_day'], 'date', 'format' => 'php:Y-m-d', 'message' => " {attribute} 格式不正确"], ]; } [/php]

PHP显示所有错误信息

最近遇到一个坑 ,由于系统环境关闭了所有错误提示并且只能在非debug模式下调试 ,所以最后采用如下方法
ini_set('display_errors',1);            //错误信息
ini_set('display_startup_errors',1);    //php启动错误信息
error_reporting(-1);                    //打印出所有的 错误信息
//如果要输出到文件就加这一句
ini_set('error_log',  '/data/runtime/error_log.txt'); //将出错信息输出到一个文本文件

PHP kafka 客户端

安装 php zookeeper 扩展 http://www.frankway.net/archives/1213 下载 https://github.com/nmred/kafka-php.git 生产者 [php] // 连接服务 $produce = \Kafka\Produce::getInstance('120.27.***.**:****,120.27.***.**:****,120.27.***.**:****', 6000); // 获取topic test-2 下可用的分区(test-2 下有2个分区) $partitions = $produce->getAvailablePartitions('test-2'); var_dump($partitions); $produce->setRequireAck(-1); // 在分区1中 添加数据 $produce->setMessages('test-2', 0, array( 'hello world 1', 'hello world 2', )); // 在分区2中 添加数据 $produce->setMessages('test-2', 1, array( 'hello world 3', 'hello world 4', )); // 插入 $result = $produce->send(); var_dump($result); [/php] 7F2E98AA-1A1A-4898-9C55-0486941FD935 消费者 [php]// 连接服务 $consumer = \Kafka\Consumer::getInstance('120.27.***.**:****,120.27.***.**:****,120.27.***.**:****'); // 设置访问用户组的名称(可以设置不同的用户组访问不同的分区内的消息) $group = 'group2'; $consumer->setGroup($group); $consumer->setFromOffset(true); //$consumer->setTopic('test-2'); //直接访问topic下分区内的所有消息 // 访问topic test-2 下的分区1 $consumer->setPartition('test-2', 1); $consumer->setMaxBytes(102400); $result = $consumer->fetch(); foreach ($result as $topicName => $partition) { foreach ($partition as $partId => $messageSet) { foreach ($messageSet as $message) { var_dump((string)$message); } } } [/php] 8CD1B648-A94C-4FF0-B51F-3B33FF8B92C4

php zookeeper 扩展安装

安装libzookeeper wget http://mirror.bit.edu.cn/apache//zookeeper/zookeeper-3.4.5/zookeeper-3.4.5.tar.gz tar -xf zookeeper-3.4.5.tar.gz cd zookeeper-3.4.5/src/c ./configure –prefix=/usr/local/zookeeper/zookeeper-3.4.5/ sudo make && make install 安装php zookeeper扩展 wget ‘http://pecl.php.net/get/zookeeper-0.2.2.tgz’ tar zxvf zookeeper-0.2.2.tgz cd zookeeper-0.2.2 /Applications/XAMPP/xamppfiles/bin/phpize ./configure –with-php-config=/Applications/XAMPP/xamppfiles/bin/php-config –with-libzookeeper-dir=/usr/local/zookeeper/zookeeper-3.4.5/ sudo make && make install sudo echo "extension=zookeeper.so" >> /Applications/XAMPP/xamppfiles/etc/php.ini

yii2 Unable to find debug data tagged with '567ca3908875f'.

把项目迁移后 发现yii2d的debug不能用了 http://local.adv.com/debug/default/toolbar?tag=567ca3908875f 显示404 查看错误信息 显示Unable to find debug data tagged with '567ca3908875f'. 解决方案 http://www.yiiframework.com/forum/index.php/topic/61689-yii-20-error-in-debug/ 将runtime目录 权限改为777