PHP extension wrapper for C++ [closed]

感情迁移 提交于 2019-12-22 11:44:29

问题


I am new in this area of writing extension for PHP, however I need to create a wrapper class for C++ to PHP. I am currently using PHP 5.2.13. I read this article http://devzone.zend.com/article/4486-Wrapping-C-Classes-in-a-PHP-Extension, a tutorial on how I could proceed to wrap C++ class to communicate with PHP Zend however it is written to for linux system. Do you guys have any article or advice on how I could proceed to write a wrapper class to communicate with PHP?


回答1:


This is exactly what I've been doing lately. The tutorial you referenced is a good one (it was my starting point as well). Here's the basic process I've followed for wrapping my classes. Say you're wrapping your C++ class named Myclass:

Create 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 */

Then define your php class in php_myclass.cpp:

#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", &param) == 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." :)
}

I hope this example code compiles, or at least helps. :) It was sort of hastily put together from real working code I have here, and if the find/replaces broke something, at least you might get an idea of what to do. There's plenty that's left out of this, read Sara Golemon's three-part extensions tutorial on http://devzone.zend.com/article/1021 for more. Good luck.




回答2:


The best "documentation" you'll find is the source code of PHP and is extensions (sorry). You'll find you have to dig into the sources (especially the headers of the Zend engine) as soon as you're doing something non-trivial.

Having said this, there are a few resources you might find useful to get you started. See these articles and Extending and Embedding PHP by Sara Golemon. See also pecl.php.net/support.php



来源:https://stackoverflow.com/questions/2445428/php-extension-wrapper-for-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!