我是这个为PHP编写扩展的领域的新手,但是我需要为PHP创建一个C ++包装类。我目前正在使用PHP 5.2.13。我读了这篇文章http://devzone.zend.com/article/4486-Wrapping-C-Classes-in-a-PHP-Extension,这是一篇关于如何将C ++类包装成与PHP Zend进行通信的教程,但它是为linux系统编写的。你们有没有关于如何编写包装类与PHP通信的文章或建议?
答案 0 :(得分:3)
这正是我最近一直在做的事情。你引用的教程很好(这也是我的出发点)。这是我为包装课程所遵循的基本过程。假设您正在包装名为Myclass
的C ++类:
创建 php_myclass.h :
#ifndef PHP_MYCLASS_H #define PHP_MYCLASS_H extern "C" { #include "php.h" } // Include your C++ class definition #include "Myclass.h" // Here is the struct which will represent the PHP version of your Myclass. // It simply includes a pointer to a Myclass and a zend_object for PHP to struct myclass_object { zend_object std; Myclass *myclass; }; // Here is whatever your PHP class is going to be called in the userspace (the PHP code) #define PHP_MYCLASS_CLASSNAME "Myclass" 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); // Later, this will be the array full of your Myclass's method declarations 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; // I'm still a newb, but I think this is the function that handles memory management when // the PHP class is deleted (goes out of scope, script ends, whatever) void myclass_free_storage(void *object TSRMLS_DC) { myclass_object *obj = (myclass_object*)object; delete obj->myclass; zend_hash_destroy(obj->std.properties); FREE_HASHTABLE(obj->std.properties); efree(obj); } // And likewise I believe this handles, as the name implies, mem management // when your Myclass is instantiated. zend_object_value myclass_create_handler(zend_class_entry *type TSRMLS_DC) { zval *tmp; zend_object_value retval; // make room in memory for a new PHP Myclass object: myclass_object *obj = (myclass_object*)emalloc(sizeof(myclass_object)); // fill that memory with 0s memset(obj, 0, sizeof(myclass_object)); obj->std.ce = type; // some magic stuff (no idea) 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*)); // make it so you can get an instance of this object in later code retval.handle = zend_objects_store_put(obj, NULL, myclass_free_storage, NULL TSRMLS_CC); retval.handlers = &myclass_object_handlers; return retval; } // First, we define some argument info for methods that take arguments (if we have any) // This one means, obviously, one argument: ZEND_BEGIN_ARG_INFO_EX(php_myclass_one_arg, 0, 0, 1) ZEND_END_ARG_INFO() // This one two args, etc. ZEND_BEGIN_ARG_INFO_EX(php_myclass_two_args, 0, 0, 2) ZEND_END_ARG_INFO() // Here's where you tell PHP what methods your Myclass PHP class has. function_entry php_myclass_functions[] = { // A special property at the end of this line for the constructor: PHP_ME(Myclass,__construct,NULL,ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) // Normal methods look like this: 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) // Three magic NULL values, no idea why they have to go here. { NULL, NULL, NULL } }; // And now, define each of those Myclass methods you just instructed PHP // to expose to the userspace: PHP_METHOD(Myclass, __construct) { Myclass *myclass = NULL; zval *object = getThis(); // Create an instance of the class you're wrapping myclass = new Myclass(); // Make object (which points to $this for your PHP object instance) // an instance of the struct that represents your php class myclass_object *obj = (myclass_object*)zend_object_store_get_object(object TSRMLS_CC); // Set the internal Myclass of this to the instance of Myclass you just made obj->myclass = myclass; // Done. } PHP_METHOD(Myclass, methodNameNoArgs) { // Get the current instance of your PHP Myclass into myclass: Myclass *myclass; myclass_object *mo = (myclass_object*)zend_object_store_get_object(getThis() TSRMLS_CC);\ myclass = mo->myclass; if (obj == NULL) { // error checking RETURN_NULL(); } // Return the value of your myclass method using one of the RETURN_* macros // Here we'll pretend this one returns boolean: RETURN_BOOL(myclass->methodNameNoArgs()); } PHP_METHOD(Myclass, methodName1Arg) { // Now, let's pretend your Myclass::methodName1Arg(int) takes an int // and returns a std::vector (which you want to be an array) long param; // Get the current instance of your PHP Myclass into myclass: Myclass *myclass; myclass_object *mo = (myclass_object*)zend_object_store_get_object(getThis() TSRMLS_CC);\ myclass = mo->myclass; if (obj == NULL) { // error checking RETURN_NULL(); } // Here's how you parse parameters of your PHP method call. // The second parameter is "l" for long int. Read the tutorials online for more // on how to use this function. if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", ¶m) == FAILURE) { RETURN_NULL(); } // Get the real return value you want to translate for PHP std::vector retval = myclass->methodName1Arg(param); // Use the magic "return_value" (which is in every method behind-the-scenes) // and initialize it to be a PHP array: array_init(return_value); // Loop through the vector and build the array: for (std::vector::iterator i = retval.begin(); i != retval.end(); ++i) { add_next_index_long(return_value, *i); } // done. return_value is always returned for you. } PHP_METHOD(Myclass, methodName2Args) { // "Left as an exercise for the reader" is coder slang for // "I *really* don't feel like typing anymore." :) }
我希望这个示例代码能够编译,或者至少有所帮助。 :)它有点匆匆从我在这里的实际工作代码拼凑而成,如果查找/替换破坏了某些东西,至少你可能会知道该怎么做。有很多内容遗留下来,请阅读Sara Golemon关于http://devzone.zend.com/article/1021的三部分扩展教程。祝你好运。
答案 1 :(得分:2)
你会发现最好的“文档”是PHP的源代码,是扩展(抱歉)。一旦你做了一件非常重要的事情,你就会发现你必须深入研究资源(特别是Zend引擎的标题)。
说了这些之后,您可能会发现一些资源可以帮助您入门。请参阅these articles和Extending and Embedding PHP by Sara Golemon。另见pecl.php.net/support.php