PHP扩展开发--编写一个helloWorld扩展 |
时间:2021-03-21 23:11:45 来源: 作者: |
为什么要用C扩展
C是静态编译的,执行效率比PHP代码高很多。同样的运算代码,使用C来开发,性能会比PHP要提升数百倍。
另外C扩展是在进程启动时加载的,PHP代码只能操作Request生命周期的数据,C扩展可操作的范围更广。 创建helloWorld函数
现在我们来创建属于自己的函数 helloWorld(),功能就是输出 Hello World!
- vim myfun/php_myfun.h
- ##在PHP_FUNCTION(confirm_myfun_compiled); 下追加一行
- PHP_FUNCTION(helloWorld);
复制代码
实现helloworld实体
- vim myfun/myfun.c
- ##zend_function_entry myfun_functions 补充要实现的函数
- const zend_function_entry myfun_functions[] = {
- PHP_FE(confirm_myfun_compiled, NULL) /* For testing, remove later. */
- PHP_FE(helloWorld, NULL) /*这是补充的一行,末尾没有逗号*/
- {NULL, NULL, NULL} /* Must be the last line in myfun_functions[] */
- };
- ##在末尾实现helloworld的内容
- PHP_FUNCTION(helloWorld)
- {
- php_printf("Hello World!\n");
- RETURN_TRUE;
- }
-
复制代码
头文件分析
- #ifndef PHP_MYFUN_H
- #define PHP_MYFUN_H
- extern zend_module_entry myfun_module_entry;
- #define phpext_myfun_ptr &myfun_module_entry
- #ifdef PHP_WIN32
- # define PHP_MYFUN_API __declspec(dllexport)
- #elif defined(__GNUC__) && __GNUC__ >= 4
- # define PHP_MYFUN_API __attribute__ ((visibility("default")))
- #else
- # define PHP_MYFUN_API
- #endif
- #ifdef ZTS
- #include "TSRM.h"
- #endif
- PHP_MINIT_FUNCTION(myfun); /*当PHP被装载时,模块启动函数即被引擎调用。这使得引擎做一些例如资源类型,注册INI变量等的一次初始化。*/
- PHP_MSHUTDOWN_FUNCTION(myfun); /*当PHP完全关闭时,模块关闭函数即被引擎调用。通常用于注销INI条目*/
- PHP_RINIT_FUNCTION(myfun); /*在每次PHP请求开始,请求前启动函数被调用。通常用于管理请求前逻辑。*/
- PHP_RSHUTDOWN_FUNCTION(myfun); /*在每次PHP请求结束后,请求前关闭函数被调用。经常应用在清理请求前启动函数的逻辑。*/
- PHP_MINFO_FUNCTION(myfun); /*调用phpinfo()时模块信息函数被呼叫,从而打印出模块信息。*/
- PHP_FUNCTION(confirm_myfun_compiled); /* For testing, remove later. */
- PHP_FUNCTION(helloWorld);
- #ifdef ZTS
- #define MYFUN_G(v) TSRMG(myfun_globals_id, zend_myfun_globals *, v)
- #else
- #define MYFUN_G(v) (myfun_globals.v)
- #endif
- #endif /* PHP_MYFUN_H */
复制代码 confirm_myfun_compiled分析
- PHP_FUNCTION(confirm_myfun_compiled) //使用了宏PHP_FUNCTION(),该宏可以生成一个适合于Zend引擎的函数原型
- {
- char *arg = NULL;
- int arg_len, len;
- char *strg;
- //获得函数传递的参数
- //第一个参数是传递给函数的参数个数。通常的做法是传给它ZEND_NUM_ARGS()。这是一个表示传递给函数参数总个数的宏。
- //第二个参数是为了线程安全,总是传递TSRMLS_CC宏。
- //第三个参数是一个字符串,指定了函数期望的参数类型,后面紧跟着需要随参数值更新的变量列表。因为PHP采用松散的变量定义和动态的类型判断,这样做就使得把不同类型的参数转化为期望的类型成为可能。例如,如果用户传递一个整数变量,可函数需要一个浮点数,那么zend_parse_parameters()就会自动地把整数转换为相应的浮点数。如果实际值无法转换成期望类型(比如整形到数组形),会触发一个警告。
- /*
- 类型指示符
- l long 符号整数
- d double 浮点数
- s char *, int 二进制字符串,长度
- b zend_bool 逻辑型(1或0)
- r zval * 资源(文件指针,数据库连接等)
- a zval * 联合数组
- o zval * 任何类型的对象
- O zval * 指定类型的对象。需要提供目标对象的类类型
- z zval * 无任何操作的zval
- */
- //第四个参数为传递的参数数据的引用
- //第五个参数为传递的参数个数
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) { //获得函数传递的参数
- return;
- }
- len = spprintf(&strg, 0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "myfun", arg);
- /*
- 通过设置RETURN_type()的方式,将返回控制到PHP。下表解释了大多数存在的宏。
- RETVAL_LONG(l) 整数
- RETVAL_BOOL(b) 布尔数(1或0)
- RETVAL_NULL() NULL
- RETVAL_DOUBLE(d) 浮点数
- RETVAL_STRING(s, dup) 字符串。如果dup为1,引擎会调用estrdup()重复s,使用拷贝。如果dup为0,就使用s
- RETVAL_STRINGL(s, l, dup) 长度为l的字符串值。与上一个宏一样,但因为s的长度被指定,所以速度更快。
- RETVAL_TRUE 返回布尔值true。注意到这个宏没有括号。
- RETVAL_FALSE 返回布尔值false。注意到这个宏没有括号。
- RETVAL_RESOURCE(r) 资源句柄。
- */
- RETURN_STRINGL(strg, len, 0);
- }
复制代码
案例2传数据版
- PHP_FUNCTION(mb_MessageBox)
- {
- char *arg = NULL;
- int arg_len, len;
- char *strg;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) {
- return;
- }
-
- len = spprintf(&strg, 0, "<script>alert('%s')</script>",arg); //此处正是输入的js代码
- RETURN_STRINGL(strg, len, 0);
- }
复制代码
|
|
|
- 修改caleng_module.c
-
- /* {{{ proto int a(int x, int y)
- */
- PHP_FUNCTION(a)
- {
- int argc = ZEND_NUM_ARGS();
- int x;
- int y;
- int z;
- if (zend_parse_parameters(argc TSRMLS_CC, "ll", &x, &y) == FAILURE)
-
- return;
- z=x+y;
- RETURN_LONG(z);
-
- }
- /* }}} */
-
- /* {{{ proto string b(string str, int n)
- */
- PHP_FUNCTION(b)
- {
- char *str = NULL;
- int argc = ZEND_NUM_ARGS();
- int str_len;
- long n;
- char *result;
- char *ptr;
- int result_length;
-
- if (zend_parse_parameters(argc TSRMLS_CC, "sl", &str, &str_len, &n) == FAILURE)
- return;
- result_length = str_len * n;
- result = (char *) emalloc(result_length + 1);
- ptr = result;
- while (n--) {
- memcpy(ptr, str, str_len);
- ptr += str_len;
- }
- *ptr = '\0';
- RETURN_STRINGL(result, result_length, 0);
-
- }
- /* }}} */
复制代码
- PHP_FUNCTION(array_square_sum)
- {
- zval* array_data;
- HashTable *ht_data;
- int ret;
- char* key;
- uint index;
- zval **pdata;
- double sum = 0;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array_data) == FAILURE) {
- return;
- }
-
- ht_data = Z_ARRVAL_P(array_data);
- zend_hash_internal_pointer_reset(ht_data);
- while ( HASH_KEY_NON_EXISTANT != (ret = zend_hash_get_current_key(ht_data, &key, &index, 0)) ) {
- ret = zend_hash_get_current_data(ht_data, &pdata);
-
- if( Z_TYPE_P(*pdata) == IS_LONG){
- sum += Z_LVAL_P(*pdata) * Z_LVAL_P(*pdata);
- }else {
- RETURN_FALSE;
- }
- zend_hash_move_forward(ht_data);
- }
- zend_hash_internal_pointer_end(Z_ARRVAL_P(array_data));
- RETVAL_DOUBLE(sum);
-
复制代码 IkI华陈数据科技 IkI华陈数据科技 IkI华陈数据科技 IkI华陈数据科技 IkI华陈数据科技
|
|
|
|