- preparations for HttpMessage
authorMichael Wallner <mike@php.net>
Tue, 12 Apr 2005 11:19:47 +0000 (11:19 +0000)
committerMichael Wallner <mike@php.net>
Tue, 12 Apr 2005 11:19:47 +0000 (11:19 +0000)
# <rant>object/property handlers suck big rocks</rant>

http.c
http_functions.c
http_message_api.c
http_methods.c
php_http.h
php_http_message_api.h
php_http_std_defs.h

diff --git a/http.c b/http.c
index 6efdedd309afdf410bd18966a3a606d63b8a2fe4..51d86d933f5a05174f4864180e7e2e30935bb0c8 100644 (file)
--- a/http.c
+++ b/http.c
@@ -159,6 +159,333 @@ zend_function_entry http_util_class_methods[] = {
 };
 /* }}} HttpUtil */
 
+/* {{{ HttpMessage */
+zend_class_entry *http_message_ce;
+static zend_object_handlers http_message_object_handlers;
+
+#define HTTP_MSG_PROPHASH_TYPE                 276192743LU
+#define HTTP_MSG_PROPHASH_HTTP_VERSION         1138628683LU
+#define HTTP_MSG_PROPHASH_RAW                  2090679983LU
+#define HTTP_MSG_PROPHASH_BODY                 254474387LU
+#define HTTP_MSG_PROPHASH_HEADERS              3199929089LU
+#define HTTP_MSG_PROPHASH_NESTED_MESSAGE       3652857165LU
+#define HTTP_MSG_PROPHASH_REQUEST_METHOD       1669022159LU
+#define HTTP_MSG_PROPHASH_REQUEST_URI          3208695486LU
+#define HTTP_MSG_PROPHASH_RESPONSE_STATUS      3857097400LU
+
+#define http_message_object_read_prop _http_message_object_read_prop
+static zval *_http_message_object_read_prop(zval *object, zval *member, int type TSRMLS_DC)
+{
+       getObjectEx(http_message_object, obj, object);
+       http_message *msg = obj->message;
+       zval *return_value;
+
+       if (!EG(scope) || !instanceof_function(EG(scope), obj->zo.ce TSRMLS_CC)) {
+               zend_error(E_WARNING, "Cannot access protected property %s::$%s", obj->zo.ce->name, Z_STRVAL_P(member));
+               return EG(uninitialized_zval_ptr);
+       }
+
+    ALLOC_ZVAL(return_value);
+    return_value->refcount = 0;
+
+#if 1
+       fprintf(stderr, "Reading property: %s(%d==%d) (%lu)\n", Z_STRVAL_P(member), Z_STRLEN_P(member), strlen(Z_STRVAL_P(member)),
+               zend_get_hash_value(Z_STRVAL_P(member), strlen(Z_STRVAL_P(member)) + 1)
+       );
+#endif
+
+       switch (zend_get_hash_value(Z_STRVAL_P(member), strlen(Z_STRVAL_P(member)) + 1))
+       {
+               case HTTP_MSG_PROPHASH_TYPE:
+                       RETVAL_LONG(msg->type);
+               break;
+
+               case HTTP_MSG_PROPHASH_HTTP_VERSION:
+                       switch (msg->type)
+                       {
+                               case HTTP_MSG_NONE:
+                                       RETVAL_NULL();
+                               break;
+
+                               case HTTP_MSG_REQUEST:
+                                       RETVAL_DOUBLE(msg->info.request.http_version);
+                               break;
+
+                               case HTTP_MSG_RESPONSE:
+                                       RETVAL_DOUBLE(msg->info.response.http_version);
+                               break;
+                       }
+               break;
+
+               case HTTP_MSG_PROPHASH_RAW:
+                       if (msg->raw) {
+                               if (msg->len) {
+                                       RETVAL_STRINGL(msg->raw, msg->len, 1);
+                               } else {
+                                       RETVAL_STRINGL(empty_string, 0, 0);
+                               }
+                       } else {
+                               RETVAL_NULL();
+                       }
+               break;
+
+               case HTTP_MSG_PROPHASH_BODY:
+                       phpstr_fix(PHPSTR(msg));
+                       RETVAL_PHPSTR(PHPSTR(msg), 0, 1);
+               break;
+
+               case HTTP_MSG_PROPHASH_HEADERS:
+                       Z_TYPE_P(return_value) = IS_ARRAY;
+                       Z_ARRVAL_P(return_value) = &msg->hdrs;
+               break;
+
+               case HTTP_MSG_PROPHASH_NESTED_MESSAGE:
+                       RETVAL_NULL();
+               break;
+
+               case HTTP_MSG_PROPHASH_REQUEST_METHOD:
+                       if (msg->type == HTTP_MSG_REQUEST && msg->info.request.method) {
+                               RETVAL_STRING(msg->info.request.method, 1);
+                       } else {
+                               RETVAL_NULL();
+                       }
+               break;
+
+               case HTTP_MSG_PROPHASH_REQUEST_URI:
+                       if (msg->type == HTTP_MSG_REQUEST && msg->info.request.URI) {
+                               RETVAL_STRING(msg->info.request.URI, 1);
+                       } else {
+                               RETVAL_NULL();
+                       }
+               break;
+
+               case HTTP_MSG_PROPHASH_RESPONSE_STATUS:
+                       if (msg->type == HTTP_MSG_RESPONSE) {
+                               RETVAL_LONG(msg->info.response.status);
+                       } else {
+                               RETVAL_NULL();
+                       }
+               break;
+
+               default:
+                       RETVAL_NULL();
+               break;
+       }
+
+       return return_value;
+}
+
+#define http_message_object_write_prop _http_message_object_write_prop
+static void _http_message_object_write_prop(zval *object, zval *member, zval *value TSRMLS_DC)
+{
+       getObjectEx(http_message_object, obj, object);
+       http_message *msg = obj->message;
+
+       if (!EG(scope) || !instanceof_function(EG(scope), obj->zo.ce TSRMLS_CC)) {
+               zend_error(E_WARNING, "Cannot access protected property %s::$%s", obj->zo.ce->name, Z_STRVAL_P(member));
+       }
+
+#if 1
+       fprintf(stderr, "Writing property: %s(%d==%d) (%lu)\n", Z_STRVAL_P(member), Z_STRLEN_P(member), strlen(Z_STRVAL_P(member)),
+               zend_get_hash_value(Z_STRVAL_P(member), strlen(Z_STRVAL_P(member)) + 1)
+       );
+#endif
+
+       switch (zend_get_hash_value(Z_STRVAL_P(member), strlen(Z_STRVAL_P(member)) + 1))
+       {
+               case HTTP_MSG_PROPHASH_TYPE:
+                       msg->type = Z_LVAL_P(value);
+               break;
+
+               case HTTP_MSG_PROPHASH_HTTP_VERSION:
+                       switch (msg->type)
+                       {
+                               case HTTP_MSG_REQUEST:
+                                       msg->info.request.http_version = (float) Z_DVAL_P(value);
+                               break;
+
+                               case HTTP_MSG_RESPONSE:
+                                       msg->info.response.http_version = (float) Z_DVAL_P(value);
+                               break;
+                       }
+               break;
+
+               case HTTP_MSG_PROPHASH_RAW:
+                       http_message_dtor(msg);
+                       http_message_parse_ex(msg, Z_STRVAL_P(value), Z_STRLEN_P(value), 1);
+               break;
+
+               case HTTP_MSG_PROPHASH_BODY:
+                       phpstr_dtor(PHPSTR(msg));
+                       phpstr_from_string_ex(PHPSTR(msg), Z_STRVAL_P(value), Z_STRLEN_P(value));
+               break;
+
+               case HTTP_MSG_PROPHASH_HEADERS:
+                       zend_hash_clean(&msg->hdrs);
+                       zend_hash_copy(&msg->hdrs, Z_ARRVAL_P(value), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
+               break;
+
+               case HTTP_MSG_PROPHASH_NESTED_MESSAGE:
+               break;
+
+               case HTTP_MSG_PROPHASH_REQUEST_METHOD:
+                       if (msg->type == HTTP_MSG_REQUEST) {
+                               if (msg->info.request.method) {
+                                       efree(msg->info.request.method);
+                               }
+                               msg->info.request.method = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value));
+                       }
+               break;
+
+               case HTTP_MSG_PROPHASH_REQUEST_URI:
+                       if (msg->type == HTTP_MSG_REQUEST) {
+                               if (msg->info.request.URI) {
+                                       efree(msg->info.request.URI);
+                               }
+                               msg->info.request.URI = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value));
+                       }
+               break;
+
+               case HTTP_MSG_PROPHASH_RESPONSE_STATUS:
+                       if (msg->type == HTTP_MSG_RESPONSE) {
+                               msg->info.response.status = Z_LVAL_P(value);
+                       }
+               break;
+       }
+}
+
+#define http_message_object_get_props _http_message_object_get_props
+static HashTable *_http_message_object_get_props(zval *object TSRMLS_DC)
+{
+       zval *headers;
+       getObjectEx(http_message_object, obj, object);
+       http_message *msg = obj->message;
+
+#define ASSOC_PROP(obj, ptype, name, val) \
+       { \
+               zval array; \
+               char *m_prop_name; \
+               int m_prop_len; \
+               Z_ARRVAL(array) = OBJ_PROP(obj); \
+               zend_mangle_property_name(&m_prop_name, &m_prop_len, "*", 1, name, lenof(name), 1); \
+               add_assoc_ ##ptype## _ex(&array, m_prop_name, sizeof(name)+4, val); \
+       }
+#define ASSOC_STRING(obj, name, val) ASSOC_STRINGL(obj, name, val, strlen(val))
+#define ASSOC_STRINGL(obj, name, val, len) \
+       { \
+               zval array; \
+               char *m_prop_name; \
+               int m_prop_len; \
+               Z_ARRVAL(array) = OBJ_PROP(obj); \
+               zend_mangle_property_name(&m_prop_name, &m_prop_len, "*", 1, name, lenof(name), 1); \
+               add_assoc_stringl_ex(&array, m_prop_name, m_prop_len, val, len, val != empty_string); \
+       }
+
+       ASSOC_PROP(obj, long, "type", msg->type);
+       ASSOC_STRINGL(obj, "raw", msg->raw, msg->len)
+       ASSOC_STRINGL(obj, "body", PHPSTR_VAL(msg), PHPSTR_LEN(msg));
+
+       MAKE_STD_ZVAL(headers);
+       array_init(headers);
+
+       zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
+       ASSOC_PROP(obj, zval, "headers", headers);
+
+       switch (msg->type)
+       {
+               case HTTP_MSG_REQUEST:
+                       ASSOC_PROP(obj, double, "httpVersion", msg->info.request.http_version);
+                       ASSOC_PROP(obj, long, "responseStatus", 0);
+                       ASSOC_STRING(obj, "requestMethod", msg->info.request.method);
+                       ASSOC_STRING(obj, "requestUri", msg->info.request.URI);
+               break;
+
+               case HTTP_MSG_RESPONSE:
+                       ASSOC_PROP(obj, double, "httpVersion", msg->info.response.http_version);
+                       ASSOC_PROP(obj, long, "responseStatus", msg->info.response.status);
+                       ASSOC_STRING(obj, "requestMethod", empty_string);
+                       ASSOC_STRING(obj, "requestUri", empty_string);
+               break;
+
+               case HTTP_MSG_NONE:
+               default:
+                       ASSOC_PROP(obj, double, "httpVersion", 0.0);
+                       ASSOC_PROP(obj, long, "responseStatus", 0);
+                       ASSOC_STRING(obj, "requestMethod", empty_string);
+                       ASSOC_STRING(obj, "requestUri", empty_string);
+               break;
+       }
+
+       return OBJ_PROP(obj);
+}
+
+#define http_message_global_init() _http_message_global_init(TSRMLS_C)
+static void _http_message_global_init(TSRMLS_D)
+{
+       http_message_object_handlers.read_property = http_message_object_read_prop;
+       http_message_object_handlers.write_property = http_message_object_write_prop;
+       http_message_object_handlers.get_properties = http_message_object_get_props;
+}
+
+#define http_message_declare_default_properties(ce) _http_message_declare_default_properties(ce TSRMLS_CC)
+static inline void _http_message_declare_default_properties(zend_class_entry *ce TSRMLS_DC)
+{
+       DCL_PROP(PROTECTED, long, type, HTTP_MSG_NONE);
+
+       DCL_PROP(PROTECTED, string, raw, "");
+       DCL_PROP(PROTECTED, string, body, "");
+
+       DCL_PROP(PROTECTED, string, requestMethod, "");
+       DCL_PROP(PROTECTED, string, requestUri, "");
+       DCL_PROP(PROTECTED, long, responseStatus, 0);
+
+       DCL_PROP_N(PROTECTED, httpVersion);
+       DCL_PROP_N(PROTECTED, headers);
+       DCL_PROP_N(PROTECTED, nestedMessage);
+}
+
+#define http_message_free_object _http_message_free_object
+void _http_message_free_object(zend_object *object TSRMLS_DC)
+{
+       http_message_object *o = (http_message_object *) object;
+
+       if (OBJ_PROP(o)) {
+               zend_hash_destroy(OBJ_PROP(o));
+               FREE_HASHTABLE(OBJ_PROP(o));
+       }
+       if (o->message) {
+               http_message_free(o->message);
+       }
+       efree(o);
+}
+
+#define http_message_new_object _http_message_new_object
+zend_object_value _http_message_new_object(zend_class_entry *ce TSRMLS_DC)
+{
+       zend_object_value ov;
+       http_message_object *o;
+
+       o = ecalloc(1, sizeof(http_message_object));
+       o->zo.ce = ce;
+       o->message = http_message_new();
+
+       ALLOC_HASHTABLE(OBJ_PROP(o));
+       zend_hash_init(OBJ_PROP(o), 0, NULL, ZVAL_PTR_DTOR, 0);
+       //zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
+
+       ov.handle = zend_objects_store_put(o, (zend_objects_store_dtor_t) zend_objects_destroy_object, http_message_free_object, NULL TSRMLS_CC);
+       ov.handlers = &http_message_object_handlers;
+
+       return ov;
+}
+
+zend_function_entry http_message_class_methods[] = {
+       PHP_ME(HttpMessage, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
+       PHP_ME(HttpMessage, __destruct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_DTOR)
+       {NULL, NULL, NULL}
+};
+/* }}} */
+
 /* {{{ HttpResponse */
 
 zend_class_entry *http_response_ce;
@@ -486,6 +813,7 @@ PHP_MINIT_FUNCTION(http)
 
 #ifdef ZEND_ENGINE_2
        HTTP_REGISTER_CLASS(HttpUtil, http_util, NULL, ZEND_ACC_FINAL_CLASS);
+       HTTP_REGISTER_CLASS_EX(HttpMessage, http_message, NULL, 0);
        HTTP_REGISTER_CLASS_EX(HttpResponse, http_response, NULL, 0);
 #      ifdef HTTP_HAVE_CURL
        HTTP_REGISTER_CLASS_EX(HttpRequest, http_request, NULL, 0);
@@ -494,6 +822,9 @@ PHP_MINIT_FUNCTION(http)
        REGISTER_LONG_CONSTANT("HTTP_HEAD", HTTP_HEAD, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("HTTP_POST", HTTP_POST, CONST_CS | CONST_PERSISTENT);
 #      endif /* HTTP_HAVE_CURL */
+
+       http_message_global_init();
+
 #endif /* ZEND_ENGINE_2 */
        return SUCCESS;
 }
index aeeea5b9eca8e35be5f30ab24fb08ce2e04e5f17..e4f3cae9cdc9bfc05d08516d17a93eccf9b60598 100644 (file)
@@ -586,7 +586,6 @@ PHP_FUNCTION(http_chunked_decode)
  *     0 => array(
  *         'Status' => '200 Ok',
  *         'Content-Type' => 'text/plain',
-
  *         'Content-Language' => 'en-US'
  *     ),
  *     1 => "Hello World!"
index a4490d8c4535b5a16d31535ebbd45b71bc7a05ed..1e6ac3a2a8e6479ffcb2398867df0a4016ee661e 100644 (file)
@@ -41,11 +41,11 @@ PHP_HTTP_API http_message *_http_message_init_ex(http_message *message, http_mes
        return message;
 }
 
-PHP_HTTP_API http_message *_http_message_parse_ex(char *message, size_t message_length, zend_bool dup TSRMLS_DC)
+PHP_HTTP_API http_message *_http_message_parse_ex(http_message *msg, char *message, size_t message_length, zend_bool dup TSRMLS_DC)
 {
        char *body = NULL;
        size_t header_length = 0;
-       http_message *msg;
+       zend_bool free_msg = msg ? 0 : 1;
 
        if (message_length < HTTP_MSG_MIN_SIZE) {
                return NULL;
@@ -55,7 +55,7 @@ PHP_HTTP_API http_message *_http_message_parse_ex(char *message, size_t message_
                return NULL;
        }
 
-       msg = http_message_new();
+       msg = http_message_init(msg);
        msg->len = message_length;
        msg->raw = dup ? estrndup(message, message_length) : message;
 
@@ -65,16 +65,18 @@ PHP_HTTP_API http_message *_http_message_parse_ex(char *message, size_t message_
        } else {
                header_length = message_length;
        }
-       
+
        if (SUCCESS != http_parse_headers_cb(message, header_length, &msg->hdrs, 1, http_message_parse_headers_callback, (void **) &msg)) {
-               http_message_free(msg);
+               if (free_msg) {
+                       http_message_free(msg);
+               }
                return NULL;
        }
-       
+
        if (body) {
                phpstr_from_string_ex(PHPSTR(msg), body, message_length - header_length);
        }
-       
+
        return msg;
 }
 
@@ -82,17 +84,17 @@ PHP_HTTP_API void _http_message_parse_headers_callback(void **message, char *htt
 {
        http_message *old = (http_message *) *message;
        http_message *new;
-       
+
        if (old->type || zend_hash_num_elements(&old->hdrs) || PHPSTR_LEN(old)) {
                new = http_message_new();
-       
+
                new->nested = old;
                *message = new;
                *headers = &new->hdrs;
        } else {
                new = old;
        }
-       
+
        // response
        if (!strncmp(http_line, "HTTP/1.", lenof("HTTP/1."))) {
                new->type = HTTP_MSG_RESPONSE;
@@ -146,14 +148,14 @@ PHP_HTTP_API void _http_message_tostring(http_message *msg, char **string, size_
                                case IS_STRING:
                                        phpstr_appendf(&str, "%s: %s" HTTP_CRLF, key, Z_STRVAL_PP(header));
                                break;
-                               
+
                                case IS_ARRAY:
                                        FOREACH_VAL(*header, single_header) {
                                                phpstr_appendf(&str, "%s: %s" HTTP_CRLF, key, Z_STRVAL_PP(single_header));
                                        }
                                break;
                        }
-                       
+
                        key = NULL;
                }
        }
@@ -176,13 +178,16 @@ PHP_HTTP_API void _http_message_dtor(http_message *message)
                phpstr_dtor(PHPSTR(message));
                if (message->raw) {
                        efree(message->raw);
+                       message->raw = NULL;
                }
                if (message->type == HTTP_MSG_REQUEST) {
                        if (message->info.request.method) {
                                efree(message->info.request.method);
+                               message->info.request.method = NULL;
                        }
                        if (message->info.request.URI) {
                                efree(message->info.request.URI);
+                               message->info.request.URI = NULL;
                        }
                }
        }
index 5fec5d834ad456d0dc4d9089c6a132f027dd49b1..8d119825be6c683fc901c44492cc455c6ae26aee 100644 (file)
@@ -517,6 +517,38 @@ PHP_METHOD(HttpResponse, send)
 /* }}} */
 /* }}} */
 
+/* {{{ HttpMessage */
+
+/* {{{ void HttpMessage::__construct([string raw_message]) */
+PHP_METHOD(HttpMessage, __construct)
+{
+       zval *message = NULL;
+       int message_len;
+       getObject(http_message_object, obj);
+       http_message *msg = obj->message;
+       
+       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z/", &message)) {
+               return;
+       }
+
+       if (message) {
+               SET_PROP(obj, raw, message);
+       }
+}
+/* }}} */
+
+/* {{{ void HttpMessage::__destruct() */
+PHP_METHOD(HttpMessage, __destruct)
+{
+       getObject(http_message_object, obj);
+       
+       NO_ARGS;
+       
+}
+/* }}} */
+
+/* }}} */
+
 #ifdef HTTP_HAVE_CURL
 /* {{{ HttpRequest */
 
index 62ae4747c148ed376b8c3ef1fd5d19544478da16..571be3789dabc5de00b77c579975f4f904e6e0ac 100644 (file)
 #ifndef PHP_EXT_HTTP_H
 #define PHP_EXT_HTTP_H
 
-#define HTTP_PEXT_VERSION "0.7.0"
+#define HTTP_PEXT_VERSION "0.8.0-dev"
 
 /* make compile on Win32 */
 #include "php_streams.h"
 #include "ext/standard/md5.h"
 #include "phpstr/phpstr.h"
+#include "php_http_message_api.h"
 
 extern zend_module_entry http_module_entry;
 #define phpext_http_ptr &http_module_entry
@@ -37,6 +38,11 @@ extern zend_module_entry http_module_entry;
 
 #ifdef ZEND_ENGINE_2
 
+typedef struct {
+       zend_object zo;
+       http_message *message;
+} http_message_object;
+
 typedef struct {
        zend_object     zo;
 } http_response_object;
@@ -88,6 +94,8 @@ PHP_METHOD(HttpUtil, postArray);
 PHP_METHOD(HttpUtil, authBasic);
 PHP_METHOD(HttpUtil, authBasicCallback);
 
+PHP_METHOD(HttpMessage, __construct);
+PHP_METHOD(HttpMessage, __destruct);
 
 PHP_METHOD(HttpResponse, __construct);/*
 PHP_METHOD(HttpResponse, __destruct);*/
index 507693f28ca70b5dbb77106f975dd8f322ff39e7..13bf62ee5f0a9a7da85517a778e2c8a40bfc334c 100644 (file)
@@ -15,6 +15,9 @@
 
 /* $Id$ */
 
+#ifndef PHP_HTTP_MESSAGE_API_H
+#define PHP_HTTP_MESSAGE_API_H
+
 /*
 DUMP:
 HttpMessage
@@ -70,9 +73,9 @@ struct _http_message {
 #define http_message_init_ex(m, t) _http_message_init_ex((m), (t))
 PHP_HTTP_API http_message *_http_message_init_ex(http_message *m, http_message_type t);
 
-#define http_message_parse(m, l) http_message_parse_ex((m), (l), 1)
-#define http_message_parse_ex(m, l, d) _http_message_parse_ex((m), (l), (d) TSRMLS_CC)
-PHP_HTTP_API http_message *_http_message_parse_ex(char *message, size_t length, zend_bool duplicate TSRMLS_DC);
+#define http_message_parse(m, l) http_message_parse_ex(NULL, (m), (l), 1)
+#define http_message_parse_ex(h, m, l, d) _http_message_parse_ex((h), (m), (l), (d) TSRMLS_CC)
+PHP_HTTP_API http_message *_http_message_parse_ex(http_message *msg, char *message, size_t length, zend_bool duplicate TSRMLS_DC);
 
 #define http_message_parse_headers_callback _http_message_parse_headers_callback
 PHP_HTTP_API void _http_message_parse_headers_callback(void *message, char *http_line, size_t line_length, HashTable **headers TSRMLS_DC);
@@ -85,6 +88,8 @@ PHP_HTTP_API void _http_message_dtor(http_message *message);
 #define http_message_free(m) _http_message_free((m))
 PHP_HTTP_API void _http_message_free(http_message *message);
 
+#endif
+
 /*
  * Local variables:
  * tab-width: 4
index a0f7ddf7b4d40104e1135436e6c02d0bb1961d43..4d9523d8a49a628ac0fa67428211fe80ff00f5a1 100644 (file)
@@ -107,7 +107,8 @@ typedef int STATUS;
                name## _ce->ce_flags |= flags;  \
        }
 
-#      define getObject(t, o) t * o = ((t *) zend_object_store_get_object(getThis() TSRMLS_CC))
+#      define getObject(t, o) getObjectEx(t, o, getThis())
+#      define getObjectEx(t, o, v) t * o = ((t *) zend_object_store_get_object(v TSRMLS_CC))
 #      define OBJ_PROP(o) o->zo.properties
 #      define DCL_PROP(a, t, n, v) zend_declare_property_ ##t(ce, (#n), sizeof(#n), (v), (ZEND_ACC_ ##a) TSRMLS_CC)
 #      define DCL_PROP_Z(a, n, v) zend_declare_property(ce, (#n), sizeof(#n), (v), (ZEND_ACC_ ##a) TSRMLS_CC)