I have a C++ object, Graph, which contains a property named cat of type Category. I’m exposing the Graph object to PHP in an extension I’m writing in C++.
As long as the Graph‘s methods return primitives like boolean or long, I can use the Zend RETURN_*() macros (e.g. RETURN_TRUE(); or RETURN_LONG(123);. But how can I make
Graph->getCategory();
return a Category object for the PHP code to manipulate?
I’m following the tutorial over at http://devzone.zend.com/article/4486, and here’s the Graph code I have so far:
#include "php_getgraph.h"
zend_object_handlers graph_object_handlers;
struct graph_object {
zend_object std;
Graph *graph;
};
zend_class_entry *graph_ce;
#define PHP_CLASSNAME "WFGraph"
ZEND_BEGIN_ARG_INFO_EX(php_graph_one_arg, 0, 0, 1)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(php_graph_two_args, 0, 0, 2)
ZEND_END_ARG_INFO()
void graph_free_storage(void *object TSRMLS_DC)
{
graph_object *obj = (graph_object*)object;
delete obj->graph;
zend_hash_destroy(obj->std.properties);
FREE_HASHTABLE(obj->std.properties);
efree(obj);
}
zend_object_value graph_create_handler(zend_class_entry *type TSRMLS_DC)
{
zval *tmp;
zend_object_value retval;
graph_object *obj = (graph_object*)emalloc(sizeof(graph_object));
memset(obj, 0, sizeof(graph_object));
obj->std.ce = type;
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*));
retval.handle = zend_objects_store_put(obj, NULL, graph_free_storage, NULL TSRMLS_CC);
retval.handlers = &graph_object_handlers;
return retval;
}
PHP_METHOD(Graph, __construct)
{
char *perspectives;
int perspectives_len;
Graph *graph = NULL;
zval *object = getThis();
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &perspectives, &perspectives_len) == FAILURE) {
RETURN_NULL();
}
graph = new Graph(perspectives);
graph_object *obj = (graph_object*)zend_object_store_get_object(object TSRMLS_CC);
obj->graph = graph;
}
PHP_METHOD(Graph, hasCategory)
{
long perspectiveId;
Graph *graph;
graph_object *obj = (graph_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
graph = obj->graph;
if (graph == NULL) {
RETURN_NULL();
}
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &perspectiveId) == FAILURE) {
RETURN_NULL();
}
RETURN_BOOL(graph->hasCategory(perspectiveId));
}
PHP_METHOD(Graph, getCategory)
{
// what to do here?
RETURN_TRUE;
}
function_entry php_getgraph_functions[] = {
PHP_ME(Graph,__construct,NULL,ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
PHP_ME(Graph,hasCategory,php_graph_one_arg,ZEND_ACC_PUBLIC)
PHP_ME(Graph,getCategory,php_graph_one_arg,ZEND_ACC_PUBLIC)
{ NULL, NULL, NULL }
};
PHP_MINIT_FUNCTION(getgraph)
{
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, PHP_CLASSNAME, php_getgraph_functions);
graph_ce = zend_register_internal_class(&ce TSRMLS_CC);
graph_ce->create_object = graph_create_handler;
memcpy(&graph_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
graph_object_handlers.clone_obj = NULL;
return SUCCESS;
}
zend_module_entry getgraph_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
PHP_GETGRAPH_EXTNAME,
NULL, /* Functions */
PHP_MINIT(getgraph),
NULL, /* MSHUTDOWN */
NULL, /* RINIT */
NULL, /* RSHUTDOWN */
NULL, /* MINFO */
#if ZEND_MODULE_API_NO >= 20010901
PHP_GETGRAPH_EXTVER,
#endif
STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_GETGRAPH
extern "C" {
ZEND_GET_MODULE(getgraph)
}
#endif
In your internal functions, you can only return zvals, not arbitrary C++ objects. In your case, you must encapsulate the Category object either in a resource or in an object (like you did for the Graph object). Either way, you cannot automatically use the C++ object’s methods and properties. You must then provide functions or methods (again, like you did for the Graph object) that then should call the underlying native methods and convert their results into zvals.
edit:
OK, I assume you’ve already declare the Category class as a PHP class, its class entry table is in
ce_categoryand you have this type:then: