php中module,编写提供对象给PHP使用的Module

还是那个关于开发安全签名的PHP模块, 今天将它包装成一个PHP的CLASS,也同样,网上的资料少之甚少,于是我想将经验写一篇,关于如何在Extension Module中创建一个可以被PHP访问的对象的文章。 和大家分享。

首先,让我们达成几个共识:

1.我的模块叫做getCookie. 使用C++编写,源文件是getCookie.cc,现在我要给它添加一个可以为PHP使用的对象;

2.DOC_ROOT 是你的扩展开发目录,比如我的扩展名字叫getCookie,那么目录就在/home/y/share/php/getCookie下;

3.我要添加的类叫做XCSecure,为什么要叫XC,因为是我名字的缩写:)

4.我的XCSecure完成一个功能,构造这个对象的时候,传入一个字符串, 返回一个以这个字符串为key,和cookie经过MD5后的字符床;

5.我假设你已经对基本的如何在linux下开发一个PHP Module很熟悉了,如果不熟悉 ,那么你可以去在网上查阅《深入PHP内核》,翻译的很不错;

现在,我们已经有一定的共识了,那么开始吧:

在PHP中,模块和PHP脚本交换数据,都是通过Zval的,我们要使用自己的C++类,就必须把我们的C++类注册为一个资源,然后每次NEW的时候,就注册一个资源实例,然后记录它的句柄到Zval中。

接下来,我们一步一步来做把。

1. 首先你要在Module中定义你自己的C++ Class。 如下:

XCSecure.h

#ifndef _XCSECURE_H_

#define _XCSECURE_H_

#include using namespace std;

class XCSecure{

private:

string _sec;

public:

XCSecure(char * s);

~XCSecure();

char * genSec();

};

#endif

然后在XCSecure.cc中定义类函数,并在getCookie.cc中也包含XCSecure.h;

2. 修改config.m4,

PHP_NEW_EXTENSION(my_module, 'my_module.cc' 'XCSecure.cc', $ext_shared);

此处要注意的是,'my_module.cc'和'XCSecure.cc'之间使用空格分割;

然后在DOC_ROOT下运行phpize,使得为我们生成configure;

然后在DOC_ROOT下运行./configure 使得为我们生成Makefile;

到这里,我们的前期工作就做好了, 你现在也可以运行make ; make install了,但只会生成一个空的module,接下来就可以填充完善它了。

3. 修改getCookie.cc,为容纳XCSecure做一些工作:

首先,我们要定义一个全局的zend_class_entry * ;

static zend_class_entry * php_xcsecure_ptr;

然后,我们要定义一个全局句柄(INT型), 我们要把我们的C++类注册成一个PHP中的资源(Resource), 在PHP中,资源是个很宽泛的概念,比如,链接Mysql的句柄,打开一个文件的句柄等等。

static int de_xcsecure;

4. 定义我们XCSecure的成员函数:

function_entry php5_secure_method[] = {

PHP_FALIAS(XCSecure, XCSecure_new, NULL)

PHP_FALIAS(genSec, XCSecure_genSec, NULL)

{NULL, NULL, NULL}

};

当然,你还需要自己定义这些函数;

5. 我选择在PHP_MINIT阶段来初始化我的类;

PHP_MINIT_FUNCTION(getCookie){

zend_class_entry php5_secure_entry;

de_php5_secure = zend_register_list_destructors_ex(_de_php5_secure, NULL, "Signature Generate Type", module_number); //为我们的C++类的对象创建析构函数,并获得它的资源类型句柄

INIT_CLASS_ENTRY(php5_secure_entry, "XCSecure", php5_secure_method);

php5_secure_entry_ptr = zend_register_internal_class(&php5_secure_entry);//注册我们的类,这样在PHP脚本中就可以使用了。

REGISTER_LONG_CONSTANT("XCSECURE_LOAD", 1, CONST_CS|CONST_PERSISTENT);

return SUCCESS;

}

首先我们创建了一个zend_class_entry, 根据变量所表达出来的意思 ,这是一个zend中的对于一个对象的操作句柄类型

然后,我们注册了我们这个对象的清理函数, 这个是因为,当在PHP脚本中unset我们的变量的时候,zend内核必须要知道如何清理我们的对象,释放我们占用的内存;

然后,我们初始化了我们的类的申明,

INIT_CLASS_ENTRY(php5_secure_entry, "XCSecure", php5_secure_method);

参数2是我们的类型名字,在PHP中var_dump的时候 ,就会显示出来,如:

object(XCSecure)#1 (0) { }

参数3是我们已经定义过的我们的类的成员函数;

然后我们向zend内核注册了我们的类,

并将它返回的指针付给了我们的全局变量(这个我自己另有用处)

zend_register_internal_class(&php5_secure_entry);

这个时候,我们的对象就算注册完成了,现在已经可以在脚本中使用了;

$xcSecure = new XCSecure('laruence');

6. 当在PHP脚本中new一个我们的对象的时候,Zend就会自动调用我们的构造函数,接下来,完成我们的构造函数:

PHP_FUNCTION(XCSecure_new){

XCSecure * instance;

char* s;

int len = 0;

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &s, &len) == FAILURE) {

RETURN_FALSE;

}

instance = new XCSecure(s);

zval * res_id;

MAKE_STD_ZVAL(res_id);

int id = ZEND_REGISTER_RESOURCE(NULL, instance, le_xc_secure);

ZVAL_LONG(res_id, id);

zend_hash_update(Z_OBJPROP_P(getThis()), Hash_Key, sizeof(Hash_Key), &res_id, sizeof(res_id), NULL);

}

首 先我们取得用户 new XCSecure($para)的参数,它是个字符串,然后,new了一个C++对象, 并注册它为一个资源实例,注意ZEND_REGISTER_RESOURCE的最后一个参数,是我们当时定义我们的资源析构函数的时候 ,返回的资源类型句柄。

然后我们把注册资源实例以后返回的资源句柄,id 保存在一个Zval中。

当用户在PHP中 创建一个我们的类的实例的时候,Zend会调用一个zend_objects_new来创建一个标准的Zend对象,并把它存入 zend_objects_store, 它是一个Bucket的数组,然后把我们的对象在数组中的索引(Zend中称为handler),存入一个zend_object_value结构,然后 把这个zend_object_value存入一个zval结构,之后,zend会再调用我们的构造函数,并且this指针指向这个zval, 所以,在我们的构造函数中,就可以通过getThis(),来获得这个zval,当然,也可以直接使用this_ptr;

注册完资源 后,构造函数就把得到的资源句柄(其实也是一个list的索引),存入this指向的zval的object的properties属性中(这是一个哈希 表),以后当用户通过我们的对象调用类函数的时候,我们就可以通过this获得这个对象,然后再通过对象的属性中的资源句柄,获得我们的C++对象。比 如:

PHP_FUNCTION(XCSecure_genSec){

zval ** rsc;

XCSecure * secure;

if(zend_hash_find(Z_OBJPROP_P(getThis()), Hash_Key, sizeof(Hash_Key), (void **)&rsc) == SUCCESS){

secure = (XCSecure *)zend_fetch_resource(NULL, Z_LVAL_PP(rsc), NULL, NULL, 1, le_xc_secure);

}

ZVAL_STRING(return_value, secure->genSec(), 1);

}

首先我们通过getThis(),取得this指针, 然后通过Z_OBJPROP_P宏,来取得this指向的zval(一个对象object)的对象的propertis属性,然后再通过zend_hash_find取得构造函数的时候保存的资源句柄。

之后,通过zend_fetch_resource取得构造函数创建的C++对象,之后你就可以象在C++中一样,随便使用这个C++对象了

7. 最后,我定义了个整型常量,这个也是另有它用;现在也可以在脚本中,访问这个常量了 ,其中的CONST_SC表明我们的这个常量是大小写敏感的,CONST_PERSISTENT顾名思义了。。

恩,到现在,我们的对象就已经加入到我们的模块中了,你现在就可以简单的make ; make install;然后来测试了 :)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值