用C++扩展PHP
2008-04-04 16:23
369 查看
前端时间写过一个Repl的PHP Extension, 记得当时在国内的中文网站上,相关的资料真的很少, 今天就抛砖引玉写一些,希望对后来者有所帮助, 那些基本的东西我就不赘述了, 主要谈谈, PHP Exitension和 PHP 之间的参数传递问题;
先说说我写的那个PHP Extension, 因为Repl(Yahoo的一个用于数据同步的工具)提供了C++ API,所以我的实现方式是, 先用C++对原有的API进行包装,以适合扩展使用, 生成一个C++的动态库.SO, 然后在PHP Extension中,简单的获取PHP传来的参数,调用有前面提及的动态库提供的API, 而问题就在于, PHP 和 PHP Extension之间的参数传递方法.
(生成动态库,你只要使用 g++ -fpic -shared 编译即可.)
1, 取得PHP传递来的参数的数量
这个问题,zend API定义了一个宏ZEND_NUM_ARGS(),
if(ZEND_NUM_ARGS() != 2) WRONG_PARAM_COUNT;
WRONG_PARAM_COUNT也是一个宏.主要负责抛出一个默认的错误信息,并返回调用者.
在zend_API.h中的定义如下,很直观了
ZEND_API void wrong_param_count(void);
#define WRONG_PARAM_COUNT { wrong_param_count(); return; }
2, 取得参数
这个用到了zend API中的一个函数:
int zend_parse_parameters(int num_args TSRMLS_DC, char *type_spec, …);
int num_args : 要接受的参数个数;并总是应该后面跟着 TSRMLS_DC;
char * type_spec : 类似与printf的格式控制字符,表明了要接受的参数的类型;
后面就紧跟着要获得参数的变量的指针;
控制字符主要的类型有:
l - 长整形
d - 双精度浮点类型
s - 字符串 (也可能是空字节)和其长度
b - 布尔型
r - 资源, 保存在 zval*
a - 数组, 保存在zval*
o - (任何类的)对象, 保存在 zval *
O - (由class entry 指定的类的)对象, 保存在 zval *
z - 实际的 zval*
下面的一些字符在类型说明字符串(就是那个char *type_spec)中具有特别的含义:
| - 表明后面的参数都是可选参数。如果用户没有传进来这些参数值,那么这些值就会被初始化成默认值。
/ - 表明前面的参数会被参数解析函数应用 SEPARATE_ZVAL_IF_NOT_REF() 方式来提供这个参数的一份拷贝,除非这些参数是一个引用。
! - 表明前面的参数允许被设定为 NULL(仅用在 a、o、O、r和z身上)。如果传进来了一个 NULL 值,则存储该参数的变量将会设置为 NULL。
来看个例子 :
/* 取得一个长整型,一个字符串和它的长度,再取得一个 zval 值。 */
long l;
char *s;
int s_len;
zval *param;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
"lsz", &l, &s, &s_len, ¶m) == FAILURE) {
return;
}
在我的扩展中,我使用了zend_get_parameters_ex() , 它将所有取回的参数都放在一个zval**(后面会讲)的结构中;
zval ** z_array;
if(FAILURE = zend_get_parameters_ex(1, &z_array){
RETURN_BOOL(0);}
而后,你就可以很控制函数对参数进行解析进行控制; 这也是我为什么选用这个的原因之一 :)
3,核心的核心,zval;
先来看看 zval的定义:
可以看出, zval中的 value是个联合体,显然它是用来容纳各种类型的值的, 相应的有个type来指明值的类型,is_ref 和 refcount是用来指明是否是引用和,引用计数的;
好到这一步,我们已经将参数的"值"取来了,现在的问题就是让它变成C++中的值(有类型);
我写的一段数组解析代码:
std::map<string, string> photo;
convert_to_array_ex(z_array);
count = zend_hash_num_elements(Z_ARRVAL_PP(z_array));
zend_hash_internal_pointer_reset(Z_ARRVAL_PP(z_array));
for (i = 0; i < count; i ++)
{
char* key;
unsigned long idx;
if (zend_hash_get_current_key(Z_ARRVAL_PP(z_array), &key, &idx, 0) == HASH_KEY_IS_STRING)
{
zend_hash_get_current_data(Z_ARRVAL_PP(z_array), (void**) &z_item);
convert_to_string_ex(z_item);
photo.insert(pair<string, string>(string(key), string(Z_STRVAL_PP(z_item))));
}
zend_hash_move_forward(Z_ARRVAL_PP(z_array));
}
今天就写这么多,改天有时间,再补。
更多内容, 可以参看 yAnbiN 的 深入 PHP 内核
做个广告,呵呵,也可以参看由我们牛X的战友Ranix翻译的Programming PHP的Extending PHP一章
//By:惠新宸 (xinchen.hui(at)alibaba-inc.com)转载请注明出处;
先说说我写的那个PHP Extension, 因为Repl(Yahoo的一个用于数据同步的工具)提供了C++ API,所以我的实现方式是, 先用C++对原有的API进行包装,以适合扩展使用, 生成一个C++的动态库.SO, 然后在PHP Extension中,简单的获取PHP传来的参数,调用有前面提及的动态库提供的API, 而问题就在于, PHP 和 PHP Extension之间的参数传递方法.
(生成动态库,你只要使用 g++ -fpic -shared 编译即可.)
1, 取得PHP传递来的参数的数量
这个问题,zend API定义了一个宏ZEND_NUM_ARGS(),
if(ZEND_NUM_ARGS() != 2) WRONG_PARAM_COUNT;
WRONG_PARAM_COUNT也是一个宏.主要负责抛出一个默认的错误信息,并返回调用者.
在zend_API.h中的定义如下,很直观了
ZEND_API void wrong_param_count(void);
#define WRONG_PARAM_COUNT { wrong_param_count(); return; }
2, 取得参数
这个用到了zend API中的一个函数:
int zend_parse_parameters(int num_args TSRMLS_DC, char *type_spec, …);
int num_args : 要接受的参数个数;并总是应该后面跟着 TSRMLS_DC;
char * type_spec : 类似与printf的格式控制字符,表明了要接受的参数的类型;
后面就紧跟着要获得参数的变量的指针;
控制字符主要的类型有:
l - 长整形
d - 双精度浮点类型
s - 字符串 (也可能是空字节)和其长度
b - 布尔型
r - 资源, 保存在 zval*
a - 数组, 保存在zval*
o - (任何类的)对象, 保存在 zval *
O - (由class entry 指定的类的)对象, 保存在 zval *
z - 实际的 zval*
下面的一些字符在类型说明字符串(就是那个char *type_spec)中具有特别的含义:
| - 表明后面的参数都是可选参数。如果用户没有传进来这些参数值,那么这些值就会被初始化成默认值。
/ - 表明前面的参数会被参数解析函数应用 SEPARATE_ZVAL_IF_NOT_REF() 方式来提供这个参数的一份拷贝,除非这些参数是一个引用。
! - 表明前面的参数允许被设定为 NULL(仅用在 a、o、O、r和z身上)。如果传进来了一个 NULL 值,则存储该参数的变量将会设置为 NULL。
来看个例子 :
/* 取得一个长整型,一个字符串和它的长度,再取得一个 zval 值。 */
long l;
char *s;
int s_len;
zval *param;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
"lsz", &l, &s, &s_len, ¶m) == FAILURE) {
return;
}
在我的扩展中,我使用了zend_get_parameters_ex() , 它将所有取回的参数都放在一个zval**(后面会讲)的结构中;
zval ** z_array;
if(FAILURE = zend_get_parameters_ex(1, &z_array){
RETURN_BOOL(0);}
而后,你就可以很控制函数对参数进行解析进行控制; 这也是我为什么选用这个的原因之一 :)
3,核心的核心,zval;
先来看看 zval的定义:
typedef pval zval; typedef struct _zval_struct zval; typedef union _zvalue_value { long lval; /* long value */ double dval; /* double value */ struct { char *val; int len; } str; HashTable *ht; /* hash table value */ struct { zend_class_entry *ce; HashTable *properties; } obj; } zvalue_value;
struct _zval_struct { /* Variable information */ zvalue_value value; /* value */ unsigned char type; /* active type */ unsigned char is_ref; short refcount; };
可以看出, zval中的 value是个联合体,显然它是用来容纳各种类型的值的, 相应的有个type来指明值的类型,is_ref 和 refcount是用来指明是否是引用和,引用计数的;
好到这一步,我们已经将参数的"值"取来了,现在的问题就是让它变成C++中的值(有类型);
我写的一段数组解析代码:
std::map<string, string> photo;
convert_to_array_ex(z_array);
count = zend_hash_num_elements(Z_ARRVAL_PP(z_array));
zend_hash_internal_pointer_reset(Z_ARRVAL_PP(z_array));
for (i = 0; i < count; i ++)
{
char* key;
unsigned long idx;
if (zend_hash_get_current_key(Z_ARRVAL_PP(z_array), &key, &idx, 0) == HASH_KEY_IS_STRING)
{
zend_hash_get_current_data(Z_ARRVAL_PP(z_array), (void**) &z_item);
convert_to_string_ex(z_item);
photo.insert(pair<string, string>(string(key), string(Z_STRVAL_PP(z_item))));
}
zend_hash_move_forward(Z_ARRVAL_PP(z_array));
}
今天就写这么多,改天有时间,再补。
更多内容, 可以参看 yAnbiN 的 深入 PHP 内核
做个广告,呵呵,也可以参看由我们牛X的战友Ranix翻译的Programming PHP的Extending PHP一章
//By:惠新宸 (xinchen.hui(at)alibaba-inc.com)转载请注明出处;
相关文章推荐
- linux下php实现C/C++扩展编程
- 用C++扩展php时函数重定义redefinition问题
- VS2012 编译 PHP C++ 扩展奇遇
- 在 windows 下 用C++ 开发 PHP 扩展
- Linux下使用C++来编写PHP扩展库
- 用C++扩展PHP - (1)
- 为PHP开发C++扩展
- [转载]用c写PHP的扩展接口(php5,c++)
- 用C/C++制作php的扩展模块(详细版)
- 用C/C++扩展你的PHP 为你的php增加功能
- linux下php实现C/C++扩展编程
- 用C++扩展PHP
- c++扩展PHP编译错误
- c/c++编写protobuf 对应的php扩展
- 用C/C++扩展你的PHP 为你的php增加功能
- C++ 开发 PHP 7 扩展之模块入口定义
- 用 C or C++ 开发PHP扩展模块
- php C++扩展的开发
- 用C/C++扩展你的PHP
- Ubuntu下C++开发PHP开发扩展的注意事项