PHP扩展开发:简单类实现
PHP扩展开发:简单类实现
话说之前有写过如何在vs2008下开发PHP扩展,今天我们来实现一个简单类。
对于一个类,一般包括类定义,声明成员变量,声明成员函数,定义类常量,
对于类继承,重载,接口实现等不在这里说明。
首先我们看下这个简单类的PHP实现:
_name;
}
public function setName($name) {
$this->_name = $name;
}
}
我们同样使用在之前创建的martin扩展
下面说明其实现过程:
1、声明类的成员函数
在php_martin.h文件中声明类的成员函数,如下所示代码:
PHP_METHOD(phppan, __construct);
PHP_METHOD(phppan, __destruct);
PHP_METHOD(phppan, getName);
PHP_METHOD(phppan, setName);
2、定义类的成员函数
在martin.c文件中给出这4个函数的实现
/** {{{
*/
PHP_METHOD(phppan, __construct) {
}
/* }}} */
/** {{{
*/
PHP_METHOD(phppan, __destruct) {
}
/* }}} */
/** {{{
*/
PHP_METHOD(phppan, getName) {
zval *self, *name;
self = getThis();
name = zend_read_property(Z_OBJCE_P(self), self, ZEND_STRL("_name"), 0 TSRMLS_CC);
RETURN_STRING(Z_STRVAL_P(name), 0);
}
/* }}} */
/** {{{
*/
PHP_METHOD(phppan, setName) {
char *arg = NULL;
int arg_len;
zval *value, *self;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) {
WRONG_PARAM_COUNT;
}
self = getThis();
MAKE_STD_ZVAL(value);
ZVAL_STRING(value, arg, arg_len, 0);
SEPARATE_ZVAL_TO_MAKE_IS_REF(&value);
zend_update_property(Z_OBJCE_P(self), self, ZEND_STRL("_name"), value TSRMLS_CC);
RETURN_TRUE;
}
/* }}} */
3、注册这些函数
/* {{{ martin_functions[]
*
* Every user visible function must have an entry in martin_functions[].
*/
const zend_function_entry martin_functions[] = {
PHP_FE(martin_echo, NULL)
PHP_ME(phppan, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
PHP_ME(phppan, __destruct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_DTOR)
PHP_ME(phppan, getName, NULL, ZEND_ACC_PUBLIC)
PHP_ME(phppan, setName, setName_args, ZEND_ACC_PUBLIC)
{NULL, NULL, NULL} /* Must be the last line in martin_functions[] */
};
/* }}} */
4、在扩展模块初始化时初始化类,并声明成员变量和常量
zend_class_entry *phppan_ce;
/* 类方法的参数 */
ZEND_BEGIN_ARG_INFO(setName_args, 0)
ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO()
/* {{{ PHP_MINIT_FUNCTION
*/
PHP_MINIT_FUNCTION(martin)
{
/* If you have INI entries, uncomment these lines
REGISTER_INI_ENTRIES();
*/
zend_class_entry phppan;
INIT_CLASS_ENTRY(phppan, "Phppan", martin_functions);
phppan_ce = zend_register_internal_class_ex(&phppan, NULL, NULL TSRMLS_CC);
/* 声明常量URL */
zend_declare_class_constant_stringl(phppan_ce, ZEND_STRL("URL"), ZEND_STRL("http://www.phppan.com") TSRMLS_CC);
/* 声明私有成员变量 _name */
zend_declare_property_null(phppan_ce, ZEND_STRL("_name"), ZEND_ACC_PRIVATE TSRMLS_CC);
return SUCCESS;
}
/* }}} */
以上为所有代码
在这些代码里面有一些东西需要说明一下:
1、类方法的定义与php的单个函数的定义一样,使用zend_function_entry结构数组,不同的是单个方法使用PHP_FE宏,
类方法的定义使用PHP_ME宏,在h文件中使用ZEND_METHOD声明,普通的函数使用ZEND_FUNCTION声明。
PHP_ME宏
定义在php.h中
#define PHP_ME ZEND_ME
#define ZEND_ME(classname, name, arg_info, flags) ZEND_FENTRY(name, ZEND_MN(classname##_##name), arg_info, flags)
2、在注册类时把该结构体作为参数交给相关的类注册方法即可
ZEND_BEGIN_ARG_INFO(setName_args, 0)
ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO()
3、取this变量使用getThis();
4、使用zend_read_property读取类成员变量,返回的是zval 指针类型
5、使用zend_update_property更新类成员变量。
6、初始化类使用INIT_CLASS_ENTRY宏
7、注册类使用zend_register_internal_class_ex函数
function registration failed duplicate name.问题的解决方法:
这个由于我们在写这个简单类时偷了一下懒,将martin_functions作为模块的函数也将它作为了类的方法。
解决方法是替换上面的martin_functions数组,增加phppan_functions,并且在注册时使用phppan_functions,在模块的functions字段使用martin_functions
/* {{{ martin_functions[]
*
* Every user visible function must have an entry in martin_functions[].
*/
const zend_function_entry martin_functions[] = {
{NULL, NULL, NULL} /* Must be the last line in martin_functions[] */
};
const zend_function_entry phppan_functions[] = {
PHP_ME(phppan, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
PHP_ME(phppan, __destruct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_DTOR)
PHP_ME(phppan, getName, NULL, ZEND_ACC_PUBLIC)
PHP_ME(phppan, setName, setName_args, ZEND_ACC_PUBLIC)
{NULL, NULL, NULL} /* Must be the last line in martin_functions[] */
};
/* }}} */
INIT_CLASS_ENTRY(phppan, "Phppan", phppan_functions);