我是 PHP 编写扩展领域的新手,但是我需要为 C++ 到 PHP 创建一个包装类。我目前正在使用 PHP 5.2.13。我读了这篇文章http://devzone.zend.com/article/4486-Wrapping-C-Classes-in-a-PHP-Extension,一个关于如何继续包装 C++ 类以与 PHP Zend 通信的教程但是它是为linux系统编写的。你们有任何关于我如何继续编写包装类来与 PHP 通信的文章或建议吗?
5539 次
2 回答
3
这正是我最近一直在做的事情。您引用的教程是一个很好的教程(这也是我的起点)。这是我包装课程所遵循的基本过程。假设您正在包装名为的 C++ 类Myclass:
创建php_myclass.h:
#ifndef PHP_MYCLASS_H
#define PHP_MYCLASS_H
外部“C”{
#include "php.h"
}
// 包括你的 C++ 类定义
#include "Myclass.h"
// 这是代表 Myclass 的 PHP 版本的结构。
// 它只包含一个指向 Myclass 的指针和一个用于 PHP 的 zend_object
结构 myclass_object {
zend_object 标准;
我的班级 *我的班级;
};
// 这是您的 PHP 类将在用户空间中调用的任何内容(PHP 代码)
#define PHP_MYCLASS_CLASSNAME "我的班级"
extern zend_class_entry *myclass_ce;
extern zend_object_handlers myclass_object_handlers;
zend_object_value myclass_create_handler(zend_class_entry *type TSRMLS_DC);
// 稍后,这将是你的 Myclass 的方法声明的数组
extern function_entry php_myclass_functions[];
#endif /* PHP_MYCLASS_H */
然后在php_myclass.cpp中定义你的 php 类:
#include "php_myclass.h"
zend_class_entry *myclass_ce;
zend_object_handlers myclass_object_handlers;
// 我还是个新手,但我认为这是处理内存管理时的函数
// PHP 类被删除(超出范围,脚本结束,等等)
void myclass_free_storage(void *object TSRMLS_DC)
{
myclass_object *obj = (myclass_object*)object;
删除 obj->myclass;
zend_hash_destroy(obj->std.properties);
FREE_HASHTABLE(obj->std.properties);
efree(obj);
}
// 同样,我相信这处理,顾名思义,内存管理
// 当你的 Myclass 被实例化时。
zend_object_value myclass_create_handler(zend_class_entry *type TSRMLS_DC)
{
zval *tmp;
zend_object_value retval;
// 在内存中为新的 PHP Myclass 对象腾出空间:
myclass_object *obj = (myclass_object*)emalloc(sizeof(myclass_object));
// 用 0 填充该内存
memset(obj, 0, sizeof(myclass_object));
obj->std.ce = 类型;
// 一些神奇的东西(不知道)
ALLOC_HASHTABLE(obj->std.properties);
zend_hash_init(obj->std.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
zend_hash_copy(obj->std.properties, &type->default_properties, (copy_ctor_func_t)zval_add_ref, (void*)&tmp, sizeof(zval*));
// 这样做,以便您可以在以后的代码中获取此对象的实例
retval.handle = zend_objects_store_put(obj, NULL, myclass_free_storage, NULL TSRMLS_CC);
retval.handlers = &myclass_object_handlers;
返回 retval;
}
// 首先,我们为接受参数的方法定义一些参数信息(如果有的话)
// 这显然意味着一个参数:
ZEND_BEGIN_ARG_INFO_EX(php_myclass_one_arg, 0, 0, 1)
ZEND_END_ARG_INFO()
// 这一个两个参数,等等。
ZEND_BEGIN_ARG_INFO_EX(php_myclass_two_args, 0, 0, 2)
ZEND_END_ARG_INFO()
// 这里告诉 PHP 你的 Myclass PHP 类有哪些方法。
函数入口 php_myclass_functions[] = {
// 此行末尾的构造函数的特殊属性:
PHP_ME(Myclass,__construct,NULL,ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
// 普通方法如下所示:
PHP_ME(Myclass,methodNameNoArgs,NULL,ZEND_ACC_PUBLIC)
PHP_ME(Myclass,methodName1Arg,php_myclass_one_arg,ZEND_ACC_PUBLIC)
PHP_ME(Myclass,methodName2Args,php_myclass_two_args,ZEND_ACC_PUBLIC)
// 三个神奇的 NULL 值,不知道为什么要放在这里。
{空,空,空}
};
// 现在,定义您刚刚指示 PHP 的每个 Myclass 方法
// 暴露给用户空间:
PHP_METHOD(Myclass, __construct)
{
我的班级 *myclass = NULL;
zval *object = getThis();
// 创建要包装的类的实例
我的班级 = 新的我的班级();
// 创建对象(指向您的 PHP 对象实例的 $this)
// 代表您的 php 类的结构实例
myclass_object *obj = (myclass_object*)zend_object_store_get_object(object TSRMLS_CC);
// 将 this 的内部 Myclass 设置为刚刚创建的 Myclass 的实例
obj->myclass = myclass;
// 完毕。
}
PHP_METHOD(Myclass, methodNameNoArgs)
{
// 将 PHP Myclass 的当前实例放入 myclass:
我的班级 *我的班级;
myclass_object *mo = (myclass_object*)zend_object_store_get_object(getThis() TSRMLS_CC);\
myclass = mo->myclass;
如果(obj == NULL){
// 错误检查
RETURN_NULL();
}
// 使用 RETURN_* 宏之一返回 myclass 方法的值
// 这里我们假设这个返回布尔值:
RETURN_BOOL(myclass->methodNameNoArgs());
}
PHP_METHOD(Myclass, methodName1Arg)
{
// 现在,假设你的 Myclass::methodName1Arg(int) 接受一个 int
// 并返回一个 std::vector (你想成为一个数组)
长参数;
// 将 PHP Myclass 的当前实例放入 myclass:
我的班级 *我的班级;
myclass_object *mo = (myclass_object*)zend_object_store_get_object(getThis() TSRMLS_CC);\
myclass = mo->myclass;
如果(obj == NULL){
// 错误检查
RETURN_NULL();
}
// 下面是解析 PHP 方法调用的参数的方法。
// 第二个参数是 "l" 表示 long int。阅读在线教程以获取更多信息
// 关于如何使用这个函数。
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", ¶m) == FAILURE) {
RETURN_NULL();
}
// 获取你想要为 PHP 翻译的真实返回值
std::vector retval = myclass->methodName1Arg(param);
// 使用魔法“return_value”(在每个方法的幕后)
// 并将其初始化为 PHP 数组:
array_init(return_value);
// 遍历向量并构建数组:
for (std::vector::iterator i = retval.begin(); i != retval.end(); ++i) {
add_next_index_long(return_value, *i);
}
// 完毕。return_value 始终为您返回。
}
PHP_METHOD(Myclass, methodName2Args)
{
// “留给读者练习”是编码器俚语
// “我*真的*不想再打字了。” :)
}
我希望这个示例代码可以编译,或者至少有帮助。:) 它是从我这里的真实工作代码中匆忙组合起来的,如果查找/替换破坏了某些东西,至少你可能会知道该怎么做。这里还有很多内容,请阅读 Sara Golemon 在http://devzone.zend.com/article/1021上的三部分扩展教程了解更多信息。祝你好运。
于 2010-05-20T17:15:16.530 回答
2
你会发现最好的“文档”是 PHP 的源代码和扩展(对不起)。您会发现,一旦您做一些不平凡的事情,就必须深入研究源代码(尤其是 Zend 引擎的标头)。
话虽如此,您可能会发现一些资源可以帮助您入门。请参阅Sara Golemon 的这些文章和扩展和嵌入 PHP 。另请参阅 pecl.php.net/support.php
于 2010-03-25T15:09:32.273 回答