msgbartop
PHP源码分析,Zend引擎分析,Web相关技术研究,Web技术分享–左手代码 右手诗
msgbarbottom

16 Apr 08 编写提供对象给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的成员函数:

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

5. 我选择在PHP_MINIT阶段来初始化我的类;
<coolcode lang="php">
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(&amp;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就会自动调用我们的构造函数,接下来,完成我们的构造函数:

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

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

&nbsp;&nbsp;&nbsp;&nbsp;当用户在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;

&nbsp;&nbsp;&nbsp;&nbsp;注册完资源 后,构造函数就把得到的资源句柄(其实也是一个list的索引),存入this指向的zval的object的properties属性中(这是一个哈希 表),以后当用户通过我们的对象调用类函数的时候,我们就可以通过this获得这个对象,然后再通过对象的属性中的资源句柄,获得我们的C++对象。比 如:
<coolcode lang="php">
PHP_FUNCTION(XCSecure_genSec){
zval ** rsc;
XCSecure * secure;
if(zend_hash_find(Z_OBJPROP_P(getThis()), Hash_Key, sizeof(Hash_Key), (void **)&amp;rsc) == SUCCESS){
secure = (XCSecure *)zend_fetch_resource(NULL, Z_LVAL_PP(rsc), NULL, NULL, 1, le_xc_secure);
}
ZVAL_STRING(return_value, secure-&gt;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;然后来测试了 :)

Related Posts:

Tags: , , ,

Leave a Comment

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word