2010-03-15 4 views
2

Je suis nouveau dans ce domaine de l'extension d'écriture pour PHP, mais j'ai besoin de créer une classe wrapper pour C++ à PHP. J'utilise actuellement PHP 5.2.13. J'ai lu cet article http://devzone.zend.com/article/4486-Wrapping-C-Classes-in-a-PHP-Extension, un tutoriel sur comment je pourrais procéder pour emballer la classe C++ pour communiquer avec PHP Zend mais il est écrit pour le système Linux. Avez-vous des articles ou des conseils sur la façon dont je pourrais écrire une classe wrapper pour communiquer avec PHP?PHP wrapper d'extension pour C++

+0

Cette question a différentes réponses maintenant –

Répondre

1

La meilleure "documentation" que vous trouverez est le code source de PHP et ses extensions (désolé). Vous trouverez que vous devez creuser dans les sources (en particulier les en-têtes du moteur Zend) dès que vous faites quelque chose de non trivial.

Cela étant dit, vous trouverez peut-être quelques ressources utiles pour vous aider à démarrer. Voir these articles et Extending and Embedding PHP by Sara Golemon. Voir aussi pecl.php.net/support.php

2

C'est exactement ce que j'ai fait récemment. Le tutoriel que vous avez référencé est bon (c'était aussi mon point de départ). Voici le processus de base que j'ai suivi pour l'emballage de mes cours. Disons que vous envelopper votre C++ classe nommée Myclass:

Créer 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 */ 

Définissez ensuite votre classe php dans 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." :) 
} 

J'espère Cet exemple de code compile, ou au moins aide. :) Il était en quelque sorte fait à la hâte à partir du vrai code de travail que j'ai ici, et si la recherche/remplacement a cassé quelque chose, au moins vous pourriez avoir une idée de ce qu'il faut faire. Il y a beaucoup de choses qui sont laissées de côté, lisez le tutoriel sur les extensions en trois parties de Sara Golemon au http://devzone.zend.com/article/1021 pour plus d'informations. Bonne chance.

+0

@ John Factoriel Merci pour la réponse. J'ai fait mon extension en utilisant ubuntu au lieu de la fenêtre maintenant et réussi à construire une extension avec l'aide de la communauté et du livre de Sara =) Mais malheureusement, j'ai un autre problème. J'ai essayé de convertir une application C++ intensive en mémoire en extension php. Cela fonctionne très bien en C++ mais en extension. Le résultat de l'extension semble toujours différent chaque fois que j'exécute. Je suspecte parce que l'objet créé n'est pas effacé. Toujours en essayant de comprendre ce problème, est-ce que n'importe quel corps a un problème avec la mémoire lors de la construction de l'extension php? – Yijinsei

+0

Comme avec tout le code C/C++, les problèmes liés à la mémoire abondent et peuvent avoir une variété de causes. Des résultats différents chaque fois que vous exécutez indique qu'une fonction peut retourner un pointeur sur une variable qui est hors de portée ou accéder d'une autre façon à de la mémoire qui n'est plus valide. En outre, PHP est souvent exécuté dans un environnement multithread, ce qui pourrait être votre problème. Impossible de savoir sans code et une meilleure description de votre problème. Je vous suggère de poser une nouvelle question à ce sujet. –