php c 扩展,实现一个PHP的C扩展 [入门篇]
准备
Linux
PHP7
PHP7源码包 点击下载
预览
Linux查看文本行数可以使用wc -l查看,
最近想尝试写PHP的C扩展,在《PHP7底层设计与源码实现》书中有一个PHP扩展的例子,这里动手实现了一下。 准备 Linux PHP7 PHP7源码包 点击下载 预览 Linux查看文本行数可以使用wc -l查看,现在需要将这一功能实现为PHP的自带功能。 假如有这样一个文本,中间有空行,要分析该文本行数,有些时候需要让函数输出3,有些时候让函数输出7(包括空行),可以通过配置php.ini文件保存这一配置。 然后在PHP中这样使用就好了: 开始 首先使用PHP7源码包中的ext_skel工具生成扩展的基本框架,进入源码包目录执行./ext_skel --extname=wcl,之后会在ext_skel同目录下生成一个wcl文件夹,其中wcl.c是扩展的主要源文件,php_wcl.h是头文件。 编辑config.m4,去掉PHP_ARG_ENABLE和[--enable-wcl]的注释dnl,我这边生成的config.m4默认是下面的样子,就不用改了。 编辑wcl.c文件: /* Every user-visible function in PHP should document itself in the source */ /* {{{ proto string confirm_wcl_compiled(string arg) Return a string to confirm that the module is compiled in */ PHP_FUNCTION(wcl) { size_t arg_len, len; int argc = ZEND_NUM_ARGS(); char *arg = NULL; if (zend_parse_parameters(argc, "s", &arg, &arg_len) == FAILURE) { return; } // zend_string *strg; // strg = strpprintf(0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "wcl", arg); // RETURN_STR(strg); FILE *fp; if ((fp = fopen(arg, "r")) == NULL) { RETURN_FALSE; } char ch, pre = '\n'; zend_long lcount = 0; while ((ch = fgetc(fp)) != EOF) { if (ch == '\n') { lcount++; } pre = ch; } fclose(fp); RETURN_LONG(lcount); } /* }}} */ /* Remove if there's nothing to do at request start */ /* {{{ PHP_RINIT_FUNCTION */ PHP_RINIT_FUNCTION(wcl) { #if defined(COMPILE_DL_WCL) && defined(ZTS) ZEND_TSRMLS_CACHE_UPDATE(); #endif return SUCCESS; } /* }}} */ /* {{{ PHP_MINFO_FUNCTION 这里是执行phpinfo()函数的输出 */ PHP_MINFO_FUNCTION(wcl) { php_info_print_table_start(); php_info_print_table_header(2, "wcl support", "enabled"); php_info_print_table_end(); /* Remove comments if you have entries in php.ini DISPLAY_INI_ENTRIES(); */ } /* }}} */ /* {{{ wcl_functions[] * * Every user visible function must have an entry in wcl_functions[]. */ const zend_function_entry wcl_functions[] = { PHP_FE(wcl, NULL) /* 注册上面定义的wcl函数*/ PHP_FE_END /* Must be the last line in wcl_functions[] */ }; /* }}} */ /* {{{ wcl_module_entry */ zend_module_entry wcl_module_entry = { STANDARD_MODULE_HEADER, "wcl", wcl_functions, PHP_MINIT(wcl), PHP_MSHUTDOWN(wcl), PHP_RINIT(wcl), /* Replace with NULL if there's nothing to do at request start */ PHP_RSHUTDOWN(wcl), /* Replace with NULL if there's nothing to do at request end */ PHP_MINFO(wcl), PHP_WCL_VERSION, STANDARD_MODULE_PROPERTIES }; /* }}} */ 计数功能主要在wcl函数中实现,无法打开文件返回false,然后按文件内容判断为换行符,计数器+1,最后返回文件行数。 之前说过对于前面的test.txt(包含多个空行),有时我们需要让函数不对空行计数php扩展,有时又需要,因此需要加载php.ini文件,将对应配置放到配置文件中由扩展加载。 编辑php_wcl.h文件: /* Declare any global variables you may need between the BEGIN and END macros here: */ ZEND_BEGIN_MODULE_GLOBALS(wcl) // filter_blank变量表示是否过滤空行,声明扩展内的全局变量 zend_long filter_blank; // char *global_string; ZEND_END_MODULE_GLOBALS(wcl) 编辑wcl.c文件 添加配置项: /* If you declare any globals in php_wcl.h uncomment this:*/ ZEND_DECLARE_MODULE_GLOBALS(wcl) // Remove comments and fill if you need to have entries in php.ini PHP_INI_BEGIN() // filter_blank变量赋默认值0 STD_PHP_INI_ENTRY("wcl.filter_blank", "0", PHP_INI_ALL, OnUpdateBool, filter_blank, zend_wcl_globals, wcl_globals) PHP_INI_END() /* }}} */ wcl函数做如下修改,使用WCL_G函数获取php.ini中对应配置项的值 char ch, pre = '\n'; zend_long lcount = 0; while ((ch = fgetc(fp)) != EOF) { if (ch == '\n') { // filter_blank in php.ini if (WCL_G(filter_blank) && pre == ch) { continue; } lcount++; } pre = ch; } 由于增加了配置项,现在要在扩展启动和销毁时对配置项做相应操作: /* {{{ PHP_MINIT_FUNCTION 配置项的注册在该阶段完成 */ PHP_MINIT_FUNCTION(wcl) { /* If you have INI entries, uncomment these lines */ REGISTER_INI_ENTRIES(); return SUCCESS; } /* }}} */ PHP_MSHUTDOWN_FUNCTION(wcl) { /* uncomment this line if you have INI entries*/ UNREGISTER_INI_ENTRIES(); return SUCCESS; } 编译生成动态链接.so文件 phpize命令需要安装php-dev phpize ./configure sudo make sudo make install 配置php.ini 执行上述过程不报错那么扩展对应的目录下会生成wcl.so文件,编辑php.ini extension=wcl.so [Wcl] wcl.filter_blank = 1 到这里wcl扩展就完成了,可以重启fpm然后直接使用wcl(filename)来测试输出。 (编辑:92站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |