From 11a67831d1000617e44e4972a12413d559a65b78 Mon Sep 17 00:00:00 2001 From: Harald Radi Date: Sat, 16 Mar 2002 16:15:34 +0000 Subject: [PATCH] blah --- ext/rpc/RPC_HOWTO | 97 +++++++++++++++++++++++++++++++++++ ext/rpc/com/com.c | 110 ++++++++++++++++++++++++++++++++++++++-- ext/rpc/handler.h | 63 +++++++++++++++++++---- ext/rpc/php_rpc.h | 6 +-- ext/rpc/rpc.c | 109 ++++++++++++++++++++++----------------- ext/rpc/rpc.h | 15 ++++-- ext/rpc/tests/test1.php | 14 ++++- 7 files changed, 342 insertions(+), 72 deletions(-) create mode 100644 ext/rpc/RPC_HOWTO diff --git a/ext/rpc/RPC_HOWTO b/ext/rpc/RPC_HOWTO new file mode 100644 index 0000000000..9b6e92b7c6 --- /dev/null +++ b/ext/rpc/RPC_HOWTO @@ -0,0 +1,97 @@ +what's this ? +============= + +This is an abstraction layer that eases the task of writing rpc +extensions (e.g. java, com, corba, soap, srm, .net, xml-rpc, ..). +it maps the quite complex ZendEngine2 oo api to a few simpler to +handle callback functions declared in the 'rpc_object_handlers' +struct. + +so what happens behind my back ? +================================ + +- the abstraction layer takes care of your underlaying data structure +and passes it to you each time you have to handle an operation. +- it does reference counting and tells you when you have to destruct +your underlaying data structure. +- it registers a class and four functions (xxx_load, xxx_call, xxx_get, +xxx_set) for your rpc layer and checks if the parameters are valid (beside +the ones that are optional for your rpc layer). +- it silently creates proxies for references to members of your rpc +objects. +- it optionally does object pooling for objects that support it (has to +be defined in the constructor) +- it optionally requests hash values for method and property names and +caches them. call / get and set requests will then receive the hash value +instead of the original function- / propertyname. + +how can i make use of it ? +========================== + +take ext/rpc/com/com.c as a starting point. you'll have to set up the following struct: + +typedef struct _rpc_object_handlers { + int (*rpc_hash)(char *name, zend_uint name_len, char **hash, zend_uint *hash_len, int type); + int hash_type; + int (*rpc_ctor)(char *class_name, zend_uint class_name_len, void **data, INTERNAL_FUNCTION_PARAMETERS); + int (*rpc_dtor)(void **data); + int (*rpc_call)(char *method_name, zend_uint method_name_len, void **data, INTERNAL_FUNCTION_PARAMETERS); + int (*rpc_get)(char *property_name, zend_uint property_name_len, zval *return_value, void **data); + int (*rpc_set)(char *property_name, zend_uint property_name_len, zval *value, zval *return_value, void **data); + int (*rpc_compare)(void **data1, void **data2); + int (*rpc_get_classname)(char **class_name, zend_uint *class_name_length, void **data); + int (*rpc_has_property)(char *property_name, zend_uint property_name_length, void **data); + int (*rpc_unset_property)(char *property_name, zend_uint property_name_length, void **data); + int (*rpc_get_properties)(HashTable **properties, void **data); +} rpc_object_handlers; + + +rpc_hash: +the hashing function for method and property names. returns a hash value +for the string passed in 'name'. 'type' is either METHOD or PROPERTY. +if you set 'hash_type' to HASH_AS_INT you can set '*hash' to NULL and pass +the hash value as 'hash_len'. +rpc_hash can be set to NULL if hashing of method and property names is not +appreciated. + +hash_type: +either HASH_AS_INT, HASH_AS_STRING or DONT_HASH + +rpc_ctor: +the constructor + +rpc_dtor: +the destructor + +rpc_call: +the call handler + +rpc_get: +the get handler + +rpc_set: +the set handler + +rpc_compare: +the compare handler. +rpc_compare can be set to NULL then objects will be treated the same if they +belong to the same rpc layer. + +rpc_get_classname: +returns the classname. +rpc_get_classname can be set to NULL then the name of the rpc layer will be +used as classname. + +rpc_has_property: +check if a property exists. +rpc_has_property can be set to NULL then true will be returned for every request. + +rpc_unset_property: +unset a property. +rpc_unset_property can be set to NULL, a 'not supported' warning will then be +issued. + +rpc_get_properties: +returns a HashTable with all the properties. +rpc_get_properties can be set to NULL, then a list of the explicit declared +properties will be returned. diff --git a/ext/rpc/com/com.c b/ext/rpc/com/com.c index c481e653ec..d43abb8f06 100644 --- a/ext/rpc/com/com.c +++ b/ext/rpc/com/com.c @@ -1,11 +1,111 @@ -#include -#include "../handler.h" -#include "../php_rpc.h" +#include "com.h" -RPC_REGISTER_HANDLERS(com) +/* protos */ +static int com_hash(char *name, zend_uint name_len, char **hash, zend_uint *hash_len, int type); +static int com_ctor(char *class_name, zend_uint class_name_len, void **data, INTERNAL_FUNCTION_PARAMETERS); +static int com_dtor(void **data); +static int com_call(char *method_name, zend_uint method_name_len, void **data, INTERNAL_FUNCTION_PARAMETERS); +static int com_get(char *property_name, zend_uint property_name_len, zval *return_value, void **data); +static int com_set(char *property_name, zend_uint property_name_len, zval *value, zval *return_value, void **data); +static int com_compare(void **data1, void **data2); +static int com_get_classname(char **class_name, zend_uint *class_name_length, void **data); +static int com_has_property(char *property_name, zend_uint property_name_length, void **data); +static int com_unset_property(char *property_name, zend_uint property_name_length, void **data); +static int com_get_properties(HashTable **properties, void **data); + +/* register rpc callback function */ +RPC_REGISTER_HANDLERS_START(com, DONT_POOL) +com_hash, +HASH_AS_STRING, +com_ctor, +com_dtor, +com_call, +com_get, +com_set, +com_compare, +com_get_classname, +com_has_property, +com_unset_property, +com_get_properties +RPC_REGISTER_HANDLERS_END() + +/* register userspace functions */ RPC_FUNCTION_ENTRY_START(com) + ZEND_FALIAS(com_invoke, rpc_call, NULL) + ZEND_FE(com_addref, NULL) RPC_FUNCTION_ENTRY_END() -RPC_INIT_FUNCTION(com) { +/* register class methods */ +RPC_METHOD_ENTRY_START(com) + ZEND_FALIAS(addref, com_addref, NULL) +RPC_METHOD_ENTRY_END() + +/* init function that is called before the class is registered + * so you can do any tricky stuff in here + */ +RPC_INIT_FUNCTION(com) +{ +} + +/* rpc handler functions */ + +static int com_hash(char *name, zend_uint name_len, char **hash, zend_uint *hash_len, int type) +{ + return SUCCESS; +} + +static int com_ctor(char *class_name, zend_uint class_name_len, void **data, INTERNAL_FUNCTION_PARAMETERS) +{ + return SUCCESS; +} + +static int com_dtor(void **data) +{ + return SUCCESS; +} + +static int com_call(char *method_name, zend_uint method_name_len, void **data, INTERNAL_FUNCTION_PARAMETERS) +{ + return SUCCESS; +} + +static int com_get(char *property_name, zend_uint property_name_len, zval *return_value, void **data) +{ + return SUCCESS; } + +static int com_set(char *property_name, zend_uint property_name_len, zval *value, zval *return_value, void **data) +{ + return SUCCESS; +} + +static int com_compare(void **data1, void **data2) +{ + return SUCCESS; +} + +static int com_get_classname(char **class_name, zend_uint *class_name_length, void **data) +{ + return SUCCESS; +} + +static int com_has_property(char *property_name, zend_uint property_name_length, void **data) +{ + return SUCCESS; +} + +static int com_unset_property(char *property_name, zend_uint property_name_length, void **data) +{ + return SUCCESS; +} + +static int com_get_properties(HashTable **properties, void **data) +{ + return SUCCESS; +} + +/* custom functions */ +ZEND_FUNCTION(com_addref) +{ +} \ No newline at end of file diff --git a/ext/rpc/handler.h b/ext/rpc/handler.h index 3e60ba77f4..51a25c86a4 100644 --- a/ext/rpc/handler.h +++ b/ext/rpc/handler.h @@ -3,46 +3,87 @@ #include "php.h" -#define RPC_HANDLER(layer) {#layer, layer##_handler_init, &layer##_object_handlers, &layer##_class_entry, layer##_function_entry} +#define RPC_HANDLER(layer) {#layer, layer##_handler_init, &layer##_object_handlers, \ + &layer##_class_entry, layer##_function_entry, \ + layer##_method_entry, &layer##_pool} #define RPC_DECLARE_HANDLER(layer) void layer##_handler_init(); \ + const int layer##_pool; \ rpc_object_handlers layer##_object_handlers; \ zend_class_entry layer##_class_entry; \ - function_entry layer##_function_entry[]; + function_entry layer##_function_entry[]; \ + function_entry layer##_method_entry[]; #define RPC_INIT_FUNCTION(layer) void layer##_handler_init() -#define RPC_REGISTER_HANDLERS(layer) zend_class_entry layer##_class_entry; \ - rpc_object_handlers layer##_object_handlers; \ +#define RPC_REGISTER_HANDLERS_START(layer, p) zend_class_entry layer##_class_entry; \ + const int layer##_pool = p; \ + rpc_object_handlers layer##_object_handlers = { + +#define RPC_REGISTER_HANDLERS_END() }; #define RPC_FUNCTION_ENTRY_START(layer) function_entry layer##_function_entry[] = { \ - PHP_FALIAS(layer##_load, rpc_load, NULL) \ - PHP_FALIAS(layer##_call, rpc_call, NULL) \ - PHP_FALIAS(layer##_get, rpc_get, NULL) \ - PHP_FALIAS(layer##_set, rpc_set, NULL) + ZEND_FALIAS(layer##_load, rpc_load, NULL) \ + ZEND_FALIAS(layer##_call, rpc_call, NULL) \ + ZEND_FALIAS(layer##_get, rpc_get, NULL) \ + ZEND_FALIAS(layer##_set, rpc_set, NULL) #define RPC_FUNCTION_ENTRY_END() {NULL, NULL, NULL} \ }; +#define RPC_METHOD_ENTRY_START(layer) function_entry layer##_method_entry[] = { + +#define RPC_METHOD_ENTRY_END() {NULL, NULL, NULL} \ + }; + +#define POOL TRUE +#define DONT_POOL FALSE +#define HASH_AS_INT TRUE +#define HASH_AS_STRING FALSE +#define DONT_HASH FALSE + +#define METHOD 0 +#define PROPERTY 1 + +/* rpc handler that have to be implemented by a + * specific rpc layer + */ typedef struct _rpc_object_handlers { - int i; + int (*rpc_hash)(char *name, zend_uint name_len, char **hash, zend_uint *hash_len, int type); + int hash_type; + int (*rpc_ctor)(char *class_name, zend_uint class_name_len, void **data, INTERNAL_FUNCTION_PARAMETERS); + int (*rpc_dtor)(void **data); + int (*rpc_call)(char *method_name, zend_uint method_name_len, void **data, INTERNAL_FUNCTION_PARAMETERS); + int (*rpc_get)(char *property_name, zend_uint property_name_len, zval *return_value, void **data); + int (*rpc_set)(char *property_name, zend_uint property_name_len, zval *value, zval *return_value, void **data); + int (*rpc_compare)(void **data1, void **data2); + int (*rpc_get_classname)(char **class_name, zend_uint *class_name_length, void **data); + int (*rpc_has_property)(char *property_name, zend_uint property_name_length, void **data); + int (*rpc_unset_property)(char *property_name, zend_uint property_name_length, void **data); + int (*rpc_get_properties)(HashTable **properties, void **data); } rpc_object_handlers; +/* handler entry */ typedef struct _rpc_handler_entry { char *name; void (*rpc_handler_init)(); rpc_object_handlers *handlers; zend_class_entry *ce; function_entry *functions; + function_entry *methods; + const int *pool_instances; } rpc_handler_entry; +/* internal data */ typedef struct _rpc_internal { zend_class_entry *ce; rpc_object_handlers **handlers; - void *data; - int refcount; + void **data; + unsigned refcount; + unsigned clonecount; + int pool_instances; } rpc_internal; #endif /* HANDLER_H */ \ No newline at end of file diff --git a/ext/rpc/php_rpc.h b/ext/rpc/php_rpc.h index 96e4e21942..be95b20940 100644 --- a/ext/rpc/php_rpc.h +++ b/ext/rpc/php_rpc.h @@ -16,9 +16,9 @@ extern zend_module_entry rpc_module_entry; #include "TSRM.h" #endif -PHP_MINIT_FUNCTION(rpc); -PHP_MSHUTDOWN_FUNCTION(rpc); -PHP_MINFO_FUNCTION(rpc); +ZEND_MINIT_FUNCTION(rpc); +ZEND_MSHUTDOWN_FUNCTION(rpc); +ZEND_MINFO_FUNCTION(rpc); ZEND_FUNCTION(rpc_load); ZEND_FUNCTION(rpc_call); diff --git a/ext/rpc/rpc.c b/ext/rpc/rpc.c index b0d5af2375..ade9afc420 100644 --- a/ext/rpc/rpc.c +++ b/ext/rpc/rpc.c @@ -27,7 +27,6 @@ static zend_object_value rpc_clone(zval *object TSRMLS_DC); static zval* rpc_read(zval *object, zval *member, int type TSRMLS_DC); static void rpc_write(zval *object, zval *member, zval *value TSRMLS_DC); static zval** rpc_get_property(zval *object, zval *member TSRMLS_DC); -static zval** rpc_get_property_zval(zval *object, zval *member TSRMLS_DC); static zval* rpc_get(zval *property TSRMLS_DC); static void rpc_set(zval **property, zval *value TSRMLS_DC); static int rpc_has_property(zval *object, zval *member, int check_empty TSRMLS_DC); @@ -48,7 +47,7 @@ static zend_object_handlers rpc_handlers = { rpc_read, rpc_write, rpc_get_property, - rpc_get_property_zval, + NULL, rpc_get, rpc_set, rpc_has_property, @@ -74,11 +73,11 @@ zend_module_entry rpc_module_entry = { STANDARD_MODULE_HEADER, "rpc", rpc_functions, - PHP_MINIT(rpc), - PHP_MSHUTDOWN(rpc), + ZEND_MINIT(rpc), + ZEND_MSHUTDOWN(rpc), NULL, NULL, - PHP_MINFO(rpc), + ZEND_MINFO(rpc), "0.1a", STANDARD_MODULE_PROPERTIES }; @@ -120,7 +119,7 @@ static int rpc_global_startup(void) /* create a class entry for every rpc handler */ INIT_OVERLOADED_CLASS_ENTRY((*(HANDLER.ce)), HANDLER.name, - NULL, + HANDLER.methods, NULL, NULL, NULL); @@ -149,9 +148,9 @@ static void rpc_globals_ctor(zend_rpc_globals *rpc_globals TSRMLS_DC) { } -/* {{{ PHP_MINIT_FUNCTION +/* {{{ ZEND_MINIT_FUNCTION */ -PHP_MINIT_FUNCTION(rpc) +ZEND_MINIT_FUNCTION(rpc) { /* GINIT */ if (thread_count++ == 0) { @@ -171,9 +170,9 @@ PHP_MINIT_FUNCTION(rpc) } /* }}} */ -/* {{{ PHP_MSHUTDOWN_FUNCTION +/* {{{ ZEND_MSHUTDOWN_FUNCTION */ -PHP_MSHUTDOWN_FUNCTION(rpc) +ZEND_MSHUTDOWN_FUNCTION(rpc) { /* GSHUTDOWN */ if (--thread_count == 0) { @@ -185,9 +184,9 @@ PHP_MSHUTDOWN_FUNCTION(rpc) } /* }}} */ -/* {{{ PHP_MINFO_FUNCTION +/* {{{ ZEND_MINFO_FUNCTION */ -PHP_MINFO_FUNCTION(rpc) +ZEND_MINFO_FUNCTION(rpc) { php_info_print_table_start(); php_info_print_table_header(2, "rpc support", "enabled"); @@ -203,7 +202,9 @@ static void rpc_instance_dtor(void *pDest) intern = (rpc_internal **) pDest; - /* TODO: destruct intern */ + /* TODO: destruct custom data */ + + pefree(*intern, TRUE); } static zend_object_value rpc_create_object(zend_class_entry *class_type TSRMLS_DC) @@ -218,7 +219,8 @@ static zend_object_value rpc_create_object(zend_class_entry *class_type TSRMLS_D /* set up the internal representation of our rpc instance */ intern = (rpc_internal *) pemalloc(sizeof(rpc_internal), TRUE); intern->ce = class_type; - intern->refcount = 0; + intern->refcount = 1; + intern->clonecount = 1; intern->data = NULL; if (zend_hash_find(handlers, class_type->name, class_type->name_length + 1, (void **) &(intern->handlers)) == FAILURE) { /* TODO: exception */ @@ -247,29 +249,48 @@ static void rpc_add_ref(zval *object TSRMLS_DC) static void rpc_del_ref(zval *object TSRMLS_DC) { - GET_INTERNAL(intern); + rpc_internal **intern; - if (RPC_REFCOUNT(intern) > 0) { - RPC_DELREF(intern); - } + if (GET_INTERNAL_EX(intern, object) == SUCCESS) { + if (RPC_REFCOUNT(intern) > 0) { + RPC_DELREF(intern); + } - if (RPC_REFCOUNT(intern) == 0) { - rpc_instance_dtor(intern); + if (RPC_REFCOUNT(intern) == 0) { + zend_hash_index_del(instance, Z_OBJ_HANDLE(*object)); + } } } static void rpc_delete(zval *object TSRMLS_DC) { - GET_INTERNAL(intern); - rpc_instance_dtor(intern); + rpc_internal **intern; + + if (GET_INTERNAL_EX(intern, object) == SUCCESS) { + if (RPC_CLONECOUNT(intern) > 0) { + RPC_DELCLONE(intern); + } + + if (RPC_CLONECOUNT(intern) == 0) { + zend_hash_index_del(instance, Z_OBJ_HANDLE_P(object)); + } + } } static zend_object_value rpc_clone(zval *object TSRMLS_DC) { -// TSRMLS_FETCH(); -// GET_INTERNAL(intern); + GET_INTERNAL(intern); + + /* cloning the underlaying resource is neither possible nor would it + * make sense, therfore we return the old zend_object_value and increase + * the clone count to not loose the clone when the original object gets + * deleted. + */ + RPC_ADDCLONE(intern); + + /* also increase the refcounter as a clone is just another reference */ + RPC_ADDREF(intern); - /* FIXME */ return object->value.obj; } @@ -289,14 +310,8 @@ static void rpc_write(zval *object, zval *member, zval *value TSRMLS_DC) static zval** rpc_get_property(zval *object, zval *member TSRMLS_DC) { -// GET_INTERNAL(intern); - - /* FIXME */ - return NULL; -} +/* no idea how to return an object - wait for andi */ -static zval** rpc_get_property_zval(zval *object, zval *member TSRMLS_DC) -{ // GET_INTERNAL(intern); /* FIXME */ @@ -342,16 +357,16 @@ static HashTable* rpc_get_properties(zval *object TSRMLS_DC) static union _zend_function* rpc_get_method(zval *object, char *method, int method_len TSRMLS_DC) { zend_function *function; + GET_INTERNAL(intern); - function = (zend_function *) emalloc(sizeof(zend_function)); - function->type = ZEND_OVERLOADED_FUNCTION; - function->common.arg_types = NULL; - function->common.function_name = method; - function->common.scope = NULL; - - // GET_INTERNAL(intern); + if (zend_hash_find(&((*intern)->ce->function_table), method, method_len + 1, &function) == FAILURE) { + function = (zend_function *) emalloc(sizeof(zend_function)); + function->type = ZEND_OVERLOADED_FUNCTION; + function->common.arg_types = NULL; + function->common.function_name = method; + function->common.scope = NULL; + } - /* FIXME */ return function; } @@ -412,7 +427,7 @@ ZEND_FUNCTION(rpc_load) /* the name of the rpc layer is prepended to '_load' so lets strip everything after * the first '_' away from the function name */ - zend_class_entry *ce; + zend_class_entry **ce; key = estrdup(get_active_function_name(TSRMLS_C)); key_len = strchr(key, '_') - key; key[key_len] = '\0'; @@ -420,7 +435,6 @@ ZEND_FUNCTION(rpc_load) /* get the class entry for the requested rpc layer */ if (zend_hash_find(CG(class_table), key, key_len + 1, (void **) &ce) == FAILURE) { /* TODO: exception here */ - RETURN_FALSE; } /* set up a new zval container */ @@ -428,18 +442,21 @@ ZEND_FUNCTION(rpc_load) INIT_PZVAL(object); Z_TYPE_P(object) = IS_OBJECT; - ZVAL_REFCOUNT(object) = 1; - PZVAL_IS_REF(object) = 1; /* create a new object */ - object->value.obj = rpc_create_object(ce TSRMLS_CC); + object->value.obj = rpc_create_object(*ce TSRMLS_CC); + /* return the newly created object */ return_value = object; /* now everything is set up the same way as if we were called as a constructor */ } - GET_INTERNAL_EX(intern, object); + if (GET_INTERNAL_EX(intern, object) == FAILURE) { + /* TODO: exception */ + } + +// (*intern)->handlers.rpc_ctor( /* FIXME */ } diff --git a/ext/rpc/rpc.h b/ext/rpc/rpc.h index bdffa8665c..5219583ead 100644 --- a/ext/rpc/rpc.h +++ b/ext/rpc/rpc.h @@ -5,16 +5,21 @@ #define HANDLER handler_entries[__handler_counter] #define HANDLER_COUNT (sizeof(handler_entries) / sizeof(rpc_handler_entry)) -#define GET_INTERNAL(intern) rpc_internal **intern; \ - GET_INTERNAL_EX(intern, object) -#define GET_INTERNAL_EX(intern, object) if (zend_hash_index_find(instance, object->value.obj.handle, (void **) &intern) == FAILURE) { \ - /* TODO: exception */ \ - } +#define GET_INTERNAL(intern) rpc_internal **intern; \ + if (GET_INTERNAL_EX(intern, object) == FAILURE) { \ + /* TODO: exception */ \ + } + +#define GET_INTERNAL_EX(intern, object) zend_hash_index_find(instance, object->value.obj.handle, (void **) &intern) #define RPC_REFCOUNT(intern) ((*intern)->refcount) #define RPC_ADDREF(intern) (++RPC_REFCOUNT(intern)) #define RPC_DELREF(intern) (--RPC_REFCOUNT(intern)) +#define RPC_CLONECOUNT(intern) ((*intern)->clonecount) +#define RPC_ADDCLONE(intern) (++RPC_CLONECOUNT(intern)) +#define RPC_DELCLONE(intern) (--RPC_CLONECOUNT(intern)) + static int __handler_counter; #endif \ No newline at end of file diff --git a/ext/rpc/tests/test1.php b/ext/rpc/tests/test1.php index 97e884bf74..e8bf24ef67 100644 --- a/ext/rpc/tests/test1.php +++ b/ext/rpc/tests/test1.php @@ -3,9 +3,19 @@ print "huhuhdsa"; $rpc = new com(); $rpc->call(); +$rpc->addref(); + +$clone = $rpc->__clone(); + +//$rpc->prop = 1; +//$a = $rpc->prop; + +$a = &$rpc->prop; + delete $rpc; +delete $clone; $heh = com_load(); -$heh->call; -delete $heh; +/*$heh->call; +delete $heh;*/ ?> \ No newline at end of file -- 2.50.1