标签归档:php

php

PHP 扩展开发之Zephir

最近对代码进行性能分析后,发现两个耗时的地方:自动加载文件数太多;参数验证函数调用超过1000次。这也是许多php语言框架面临的问题,所以发展出来诸如YafSwoolePhalcon这些C语言扩展框架,或者类似workermanreactphpphpdaemon这些一次加载的框架。总之减少加载文件,使用内置函数,减少损耗,以提升性能。
相比之下,PHP扩展的框架性能还是要比PHP语言框架还要好不少。以往PHP扩展的开发方式就是C/C++SWIG,现在还多了一个选择:zephir,从Phalcon发展出来的项目,采用类似PHP语法的中间语言,将代码编译为高性能的C扩展。zephir支持面向对象编程,变量类型除了类似PHP的动态类型,还支持静态类型(有点像FackBook的hack了),而且可以调用php内置或其他C扩展的函数。zephir编译流程如下
scheme
整个过程是zephir和底层编译器自动进行编译优化的,当然也可以自己调整以获得更好的性能。
在ubuntu下的安装如官方教程即可,在centos下的安装如下

su -c 'yum update'
sudo yum install -y wget 
sudo yum install -y vim 
sudo yum install -y libtool
sudo yum install -y gcc 
sudo yum install -y make 
sudo yum install -y re2c

sudo rpm -Uvh https://mirror.webtatic.com/yum/el6/latest.rpm
sudo yum install -y php55w 
sudo yum install -y php55w-devel 
sudo yum install -y php55w-json

sudo yum install -y git-core 

git clone https://github.com/json-c/json-c.git
cd json-c
./autogen.sh
./configure
make
make install

git clone https://github.com/phalcon/zephir
cd zephir
./install -c
zephir help

安装完成如下:
zephir10
按照教程创建示例:

zephir init utils
cd utils
sudo vim utils/greeting.zep

greeting.zep代码如下:

namespace Utils;

class Greeting
{

    public static function say()
    {
        echo "hello world!";
    }

}

编译安装

$ zephir build

注意,我在php5.3下面这么编译都不行,在php5.5/php5.4的版本基本没有碰到什么问题。
然后更改php.ini:

sudo vim /etc/php.ini

在php.ini中加上以下内容

;zephir编译的扩展需要依赖json.so,需要提前加载
[json]
;如果php.ini中没有则加上,有则去掉;
extension=json.so

[utils]
extension=utils.so 

查看php可用扩展

php -i

注意:如果提示’undefined symbol: php_json_decode_ex in Unknown on line 0’,则是php json扩展未加载,在php.ini打开就行了。加载了json.so后又提示’PHP Warning: Module ‘json’ already loaded’,则是已经在其他地方加载了该扩展,找出并注释掉。我的是在php.d下面的json.ini里面:

sudo vim /etc/php.d/json.ini
[json]
;已经在php.ini中加载了,为避免重复加载注释掉
;extension = json

加载成功后的效果:
zephir3
创建一个php脚本来试一下

cd ~/utils
sudo vim greeting.php

greeting.php代码如下:

<?php

echo Utils\Greeting::say(), "\n";

保存并运行:
zephir11
zephir5
zephir6
至此你的zephir编译的扩展已经成功了,赶紧翻译你的PHP代码去吧。
参考这篇教程,计算斐波拉契数列在我的环境下是这样的:
zephir13
性能提升还是挺明显的,而且在静态类型(强类型)下面还能比动态类型再提升。

参考链接:
开源的 PHP 轻量级框架 iphp
自己写PHP扩展之创建一个类
快速开发一个PHP扩展
CentOS 5 or CentOS 6 Upgrade PHP to PHP 5.4 or PHP 5.5
PHP 開發者應該將 Zephir 列為重要觀察的專案
Hack: a new programming language for HHVM
PHP-CPP
Getting Started with PHP Extension Development via Zephir
Quick Tip: Install Zephir and Phalcon 2 on Vagrant

PHP unserialize出错

最近碰到一个问题,在使用PHP的unserialize函数反序列化服务端传递过来的参数时报错了:unserialize() [function.unserialize]: Error at offset 180 of 181 bytes。最后在Stackoverflow上找到了一个非常好的答案:这是由于序列化时字符串长度算错了导致的。作者还写了个校正长度的正则表达式,提供了一个用于计算序列化是否出错了的函数。导致序列化出错的原因通常是因为内容使用了双引号(”)而不是单引号(’),php与mysql编码不一致(UTF8),内容包括冒号(:)和引号(;)也会导致反序列化出错。
解决的方法是在serialize上加上base64函数,对数据做base64编码和解码:

$toDatabse = base64_encode(serialize($data));
$fromDatabase = unserialize(base64_decode($data)); 

当然更建议使用json_encode和json_decode的来处理数据的序列化和反序列化会更快,但有一些局限性(这里)继续阅读

PHP 和 Mysql 日期问题

最近在php 和 mysql上碰到了一个计算日期Bug:在mysql中使用date_add计算日期,比如date_add(now(),interval 30 year),然后保存进去的值就变成了’0000-00-00 00:00:00’;在php 中使用strtotime计算日期,比如(‘2143-08-22 15:23:56 -100 year’),然后格式化后就变成了’1970-01-01 ‘。后来google了下,发现这是著名的2038年问题
这个问题是因为在32位操作系统上日期类型是一个有正负号的32位整数,2147483647 是能表示的最大32为正整数,对应2038-01-19 03:14:07,超出了就“绕回”,所以不能正常处理。 继续阅读

PHP __destruct函数

PHP引擎会在脚本执行完成后进行垃圾回收,那么是否还需要destruct呢?在stackoverflow上看到的一个很好的答复

析构函数本身跟内存释放没有任何直接的关系,它只是当一个对象被回收时执行自定义代码的“钩子”。它的作用跟构造函数刚好相反-构造函数本身也不申请内存(内存的申请和释放都是GC的事)。
GC能够很好的管理PHP原生的资源(比如对象),但是对于外部资源却必须手动处理。比如,一个文件管理的类,析构函数的作用就是保证如果文件被打开了,就应该被关闭。虽然“最好”在一个对象上要求去调用一个关闭或处理操作,这时析构函数就作为一种援助机制。
我本身反对将析构函数与GC一起使用。有许多微妙的问题他们可以引入如明显的非确定性和意外的能力保持对象存活——甚至在像PHP这种使用引用计数的语言里面。(Java/JVM和.net使用终结器更为挑剔。)

继续阅读

PHP strtotime计算月份

今天同事发现了一个php的月份bug,说月份列表里怎么出现了两个3月份,代码是大概是这样的:

$month[]=date('Y年m月',strtotime('today'));
$month[]=date('Y年m月',strtotime('-1 month'));
$month[]=date('Y年m月',strtotime('-2 month'));
$month[]=date('Y年m月',strtotime('-3 month'));
$month[]=date('Y年m月',strtotime('-4 month'));
$month[]=date('Y年m月',strtotime('-5 month'));

利用strtotime来计算最近了六个月份,这个bug之前没有被发现因为只有在每月的29,30,31号才会发作:因为php默认取当前时间来做计算,比如今天7月29号减去5个月应该是2月29号,因为今年的2月份没有29号,所以就到了3月份了。 继续阅读