我是 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 回答