J'ai récemment commencé à chercher à écrire des extensions PHP et j'ai lu this article, qui décrit un point de départ pour construire une extension en C++. Comme j'ai commencé à personnaliser, j'ai rencontré un problème en essayant de partager certaines fonctionnalités dans un fichier séparé. Tout compile et relie sans problèmes, mais une erreur se produit lorsque j'essaie d'utiliser réellement l'extension. Le message exact est:PHP Extension avec C++
$ php -dextension=test.so -r "var_dump(new Test);"
php: symbol lookup error: /etc/php/ext/test.so: undefined symbol: _ZN9ContainerI4TestEC1EP17_zend_class_entry
J'ai essayé ceci sur deux ordinateurs et les deux éprouvent le même problème. Je comprends qu'il ne peut pas trouver l'implémentation réelle pour le constructeur Container, mais je ne sais pas comment l'obtenir au bon endroit.
J'ai essayé de découper autant de fluff que je peux avant de poster ici, mais il y a encore beaucoup de cruft dans le code d'interface php. Le code est le suivant:
config.m4:
PHP_ARG_ENABLE(test,
[Whether to enable the "test" extension],
[ --enable-test Enable "test" extension support])
if test $PHP_TEST != "no"; then
PHP_REQUIRE_CXX()
PHP_SUBST(TEST_SHARED_LIBADD)
PHP_ADD_LIBRARY(stdc++, 1, TEST_SHARED_LIBADD)
PHP_NEW_EXTENSION(test, interface.cpp internals.cpp, $ext_shared)
fi
interface.h:
#ifndef INTERFACE_H_
#define INTERFACE_H_
#define PHP_TEST_EXTNAME "test"
#define PHP_TEST_EXTVER "0.1"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#endif
interface.cpp:
#include "interface.h"
#include "internals.h"
#include "php.h"
class Test {};
extern zend_module_entry test_module_entry;
zend_object_handlers test_object_handlers;
zend_class_entry *test_ce;
void test_free_storage(void *object TSRMLS_DC)
{
delete (Container<Test> *) object;
}
zend_object_value test_create_handler(zend_class_entry* classInfo TSRMLS_DC)
{
Container<Test> *obj = new Container<Test>(classInfo);
zend_object_value retval;
retval.handle = zend_objects_store_put(
obj, NULL, test_free_storage, NULL TSRMLS_CC
);
retval.handlers = &test_object_handlers;
return retval;
}
PHP_METHOD(Test, __construct)
{
Test* test = new Test;
Container<Test> *obj = (Container<Test> *) zend_object_store_get_object(getThis() TSRMLS_CC);
obj->cpp = test;
}
function_entry test_methods[] = {
PHP_ME(Test, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
{NULL, NULL, NULL}
};
PHP_MINIT_FUNCTION(test)
{
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "Test", test_methods);
test_ce = zend_register_internal_class(&ce TSRMLS_CC);
test_ce->create_object = test_create_handler;
memcpy(
&test_object_handlers,
zend_get_std_object_handlers(),
sizeof(zend_object_handlers)
);
test_object_handlers.clone_obj = NULL;
return SUCCESS;
}
zend_module_entry test_module_entry = {
STANDARD_MODULE_HEADER,
PHP_TEST_EXTNAME,
NULL, /* Functions */
PHP_MINIT(test), /* MINIT */
NULL, /* MSHUTDOWN */
NULL, /* RINIT */
NULL, /* RSHUTDOWN */
NULL, /* MINFO */
PHP_TEST_EXTVER,
STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_TEST
extern "C" {
ZEND_GET_MODULE(test)
}
#endif
internals.h:
#ifndef INTERNALS_H_
#define INTERNALS_H_
#include "zend.h"
template <class T>
class Container
{
private:
zend_object zend;
public:
T* cpp;
Container (zend_class_entry* classInfo);
};
#endif /* INTERNALS_H_ */
internals.cpp
#include "internals.h"
#include "zend.h"
template <class T>
Container<T>::Container (zend_class_entry* classInfo)
: zend()
{
zend.ce = classInfo;
}
Je construis à l'aide des commandes suivantes:
$ phpize
$ ./configure --enable-test
$ make && make install
$ php -dextension=test.so -r "var_dump(new Test);"
Merci pour toute aide que vous pouvez offrir
Cela a du sens. Je ne peux pas dire que j'aime polluer mes fichiers d'en-tête comme ça, mais ça a marché et je ne suis pas le concepteur de langage.Merci pour votre aide – Nycto