2 Stimmen

PHP-Erweiterungs-Wrapper für C++

Ich bin neu in diesem Bereich des Schreibens Erweiterung für PHP, jedoch muss ich eine Wrapper-Klasse für C++ zu PHP erstellen. Ich verwende derzeit PHP 5.2.13. Ich habe diesen Artikel gelesen http://devzone.zend.com/article/4486-Wrapping-C-Classes-in-a-PHP-Extension ein Tutorial, wie ich vorgehen könnte, um C++ Klasse zu wickeln, um mit PHP Zend kommunizieren, aber es ist für Linux-System geschrieben. Haben Sie irgendwelche Artikel oder Ratschläge, wie ich gehen könnte, um eine Wrapper-Klasse zu schreiben, um mit PHP zu kommunizieren?

3voto

John Factorial Punkte 155

Das ist genau das, was ich in letzter Zeit gemacht habe. Das Tutorial Sie verwiesen ist eine gute (es war mein Ausgangspunkt als gut). Hier ist der grundlegende Prozess, den ich für das Wrapping meiner Klassen gefolgt bin. Angenommen, Sie wickeln Ihre C++-Klasse namens Myclass :

erstellen. 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 \*/

Dann definieren Sie Ihre php-Klasse 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", ¶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." :)
}

Ich hoffe, dieser Beispielcode lässt sich kompilieren oder hilft zumindest. :) Es wurde irgendwie hastig aus echtem, funktionierendem Code zusammengestellt, den ich hier habe, und wenn das Finden/Ersetzen etwas kaputt gemacht hat, bekommt man zumindest eine Idee davon, was zu tun ist. Es gibt viele Dinge, die hier ausgelassen wurden, lesen Sie Sara Golemons dreiteiliges Extensions-Tutorial auf http://devzone.zend.com/article/1021 für mehr. Viel Glück!

2voto

Artefacto Punkte 93200

Die beste "Dokumentation", die Sie finden werden, ist der Quellcode von PHP und seine Erweiterungen (sorry). Sie werden feststellen, dass Sie in den Quellen (insbesondere in den Headern der Zend-Engine) graben müssen, sobald Sie etwas nicht-triviales tun.

Dennoch gibt es einige Ressourcen, die Ihnen den Einstieg erleichtern können. Siehe diese Artikel et Erweitern und Einbetten von PHP von Sara Golemon . Siehe auch pecl.php.net/support.php

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X