用C++扩展PHP

     前端时间写过一个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, &param) == 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)转载请注明出处;

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值