第一个有点做用的PHP扩展

C/C++去开发PHP扩展

我觉的对于PHP开发人员来讲,学的东西很是杂,也很是多,固然了开发PHP扩展也是一个必需要掌握的技能,这里膜拜下大神鸟哥(Laruence)~
今天要开发的第一个有点功能的扩展,主要做用是记录日志的时候生成日志前面的日期部分php

#即便当前的时间,年-月-日 时:分:秒 时间戳.微妙数 
[2015-05-19 20:39:32 1432039172.968199]

php扩展函数前奏

首先生成”骨架“:
1. 进入php源码src/ext目录下面
2. 运行./ext_skel --extname=mytest
3. 进入src/ext/mytest/目录
4. 在编写扩展的时候要先修改下config.me文件的10-12行,去掉前面的dnl注释,这个网上一搜一大把。
在头文件php_mttest.h中声明要编写的php扩展函数名
PHP_FUNCTION(get_log_title);
#PHP_FUNCTION是PHP内核中声明的一个宏
#define PHP_FUNCTION        ZEND_FUNCTION    //在文件src/main/php.h : 347行
#define ZEND_FUNCTION(name) ZEND_NAMED_FUNCTION(ZEND_FN(name))      //文件src/Zend/zend_API.h : 68行
#define ZEND_FN(name)       zif_##name      //文件src/Zend/zend_API.h : 65行
#define ZEND_NAMED_FUNCTION(name) void name(INTERNAL_FUNCTION_PARAMETERS)   //文件src/Zend/zend_API.h : 67行
#define INTERNAL_FUNCTION_PARAMETERS int ht, zval *return_value, zval **return_value_ptr, zval *this_ptr, int return_value_used TSRMLS_DC   //src/Zend/zend.h : 290行

上面的声明函数宏展开后是:函数

void zif_get_log_title( int ht, zval *return_value, zval **return_value_ptr, zval *this_ptr, int return_value_used TSRMLS_DC)
在mytest.c中的zend_function_entry声明中添加get_log_title函数的声明
const zend_function_entry logs_functions[] = {
        PHP_FE(confirm_logs_compiled,   NULL)           /* For testing, remove later. */
        PHP_FE(get_log_title, NULL)
        PHP_FE_END      /* Must be the last line in logs_functions[] */
};
#编写函数
PHP_FUNCTION(get_log_title)
{
    struct timeval tv;
    time_t rawtime;
    struct tm *timeinfo;
    char *formatinfo;
    time(&rawtime);
    timeinfo = localtime(&rawtime);
    gettimeofday(&tv, NULL);
    spprintf(&formatinfo, 0, "[%4d-%02d-%02d %d:%d:%d %d.%d]", 1900 + timeinfo->tm_year, 1 + timeinfo->tm_mon, timeinfo->tm_mday, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, tv.tv_sec, tv.tv_usec);
    RETURN_STRING(formatinfo, 1);
}

这里还要看个宏RETURN_STRING测试

#define RETURN_STRING(s, duplicate)     { RETVAL_STRING(s, duplicate); return; }        //文件src/Zend/zend_API.h : 635行
#define RETVAL_STRING(s, duplicate)     ZVAL_STRING(return_value, s, duplicate)         //文件src/Zend/zend_API.h : 623行
#define ZVAL_STRING(z, s, duplicate) do {   \   //文件src/Zend/zend_API.h : 577-583行,这个的做用实际上是给一个string类型zval变量赋值
    const char *__s=(s);                \       
    zval *__z = (z);                    \
    Z_STRLEN_P(__z) = strlen(__s);      \       //设置zval字符串长度
    Z_STRVAL_P(__z) = (duplicate?estrndup(__s, Z_STRLEN_P(__z)):(char*)__s);\   //设置zval字符串的值
    Z_TYPE_P(__z) = IS_STRING;          \       //设置zval字符串的类型为字符串
} while (0)

所以,RETURN_STRING(formatinfo, 1)展开后为:this

do {
    const char *__s=(formatinfo);
    zval *__z = (return_value);         //这里面的return_value估计是内核定义的,相似 zval *return_value;
    (*__z).value.str.len = strlrn(__s);     //等价于__z->value.str.len
    (*__z).value.str.val = (1?estrndup(__s, (*__z).value.str.len):(char*)__s);
    (*__z).type = 6;    
}
编译测试
编译的时候须要安装好的php,好比个人php安装在/usr/local/php/目录下面

cd mytest;      //今日刚才编写的函数扩展目录
/usr/local/php/bin/phpize   //运行phpize,生成configure文件
./configure --with-php-config=/usr/local/php/bin/php-config     //configure,后面的--with-php-config会生成so文件到安装好的扩展目录,固然也能够不用加,声称以后手动copy过去
make    //有错误的话修正
make install    //运行以后会提示相似下面的内容
#Installing shared extensions:     /usr/local/php/lib/php/extensions/no-debug-non-zts-20100525/
#修改配置文件php.ini添加extension = mytest.so
#测试
php -r 'var_dump(log_get_title());'

输出下面内容的话,恭喜你成功了debug

[root@iforever logs]# php -r 'var_dump(get_log_title());' && date
string(39) "[2015-05-19 22:52:29 1432047149.755613]"
2015年 05月 19日 星期二 22:52:29 CST

5/19/2015 10:54:38 PM日志

本文版权归做者iforever(luluyrt@163.com)全部,未经做者本人赞成禁止任何形式的转载,转载文章以后必须在文章页面明显位置给出做者和原文链接,不然保留追究法律责任的权利。code

相关文章
相关标签/搜索