← 回到文章

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);

最后更新于 2012-02-23 22:00:28