It looks like I stripped off too much. Attached is the right one. Moriyoshi On Sun, Mar 14, 2010 at 12:41 AM, Moriyoshi Koizumi <mozo@mozo.jp> wrote: > Surprisingly, It can be done quite easily with the current object> handler infrastructure.>> Moriyoshi>> On Sun, Mar 14, 2010 at 12:08 AM, Pierre Joye <pierre.php@gmail.com> wrote:>> On Sat, Mar 13, 2010 at 3:13 PM, Moriyoshi Koizumi <mozo@mozo.jp> wrote:>>>>> I don't totally agree with what is being said here, but I guess we>>> don't have to make Unicode a first-class value. Once operator>>> overloading is supported, Unicode strings can be represented as>>> objects, like Python does although I didn't have a look at past>>> discussion on this topic.>>>> Operators overloading, while being a cool feature, should not be>> associated with Unicode&related features. Or we are going to do the>> exact same mistakes than before, way too many changes, features, work>> to even get a visible deadline for the next major release.>>>> Cheers,>> -->> Pierre>>>> @pierrejoye | http://blog.thepimp.net | http://www.libgd.org>>>
diff --git a/Zend/zend.h b/Zend/zend.h index 38f461c..0ffcb1a 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -442,6 +442,7 @@ struct _zend_class_entry { union _zend_function *__call; union _zend_function *__callstatic; union _zend_function *__tostring; + union _zend_function *__concat; union _zend_function *serialize_func; union _zend_function *unserialize_func; diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 5433dc1..e0dcd73 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -1799,7 +1799,7 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio int count=0, unload=0; HashTable *target_function_table = function_table; int error_type; - zend_function *ctor = NULL, *dtor = NULL, *clone = NULL, *__get = NULL, *__set = NULL, *__unset = NULL, *__isset = NULL, *__call = NULL, *__callstatic = NULL, *__tostring = NULL; + zend_function *ctor = NULL, *dtor = NULL, *clone = NULL, *__get = NULL, *__set = NULL, *__unset = NULL, *__isset = NULL, *__call = NULL, *__callstatic = NULL, *__tostring = NULL, *__concat = NULL; char *lowercase_name; int fname_len; char *lc_class_name = NULL; @@ -1929,6 +1929,8 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio __unset = reg_function; } else if ((fname_len == sizeof(ZEND_ISSET_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_ISSET_FUNC_NAME, sizeof(ZEND_ISSET_FUNC_NAME))) { __isset = reg_function; + } else if ((fname_len == sizeof(ZEND_CONCAT_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_CONCAT_FUNC_NAME, sizeof(ZEND_CONCAT_FUNC_NAME))) { + __concat = reg_function; } else { reg_function = NULL; } @@ -1967,6 +1969,7 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio scope->__set = __set; scope->__unset = __unset; scope->__isset = __isset; + scope->__concat = __concat; if (ctor) { ctor->common.fn_flags |= ZEND_ACC_CTOR; if (ctor->common.fn_flags & ZEND_ACC_STATIC) { @@ -2030,6 +2033,12 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio } __isset->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC; } + if (__concat) { + if (__concat->common.fn_flags & ZEND_ACC_STATIC) { + zend_error(error_type, "Method %s::%s() cannot be static", scope->name, __concat->common.function_name); + } + __concat->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC; + } efree(lc_class_name); } return SUCCESS; diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 13b6c55..91cd34a 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1267,6 +1267,10 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n } else if ((name_len == sizeof(ZEND_TOSTRING_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_TOSTRING_FUNC_NAME, sizeof(ZEND_TOSTRING_FUNC_NAME)-1))) { if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { zend_error(E_WARNING, "The magic method __toString() must have public visibility and cannot be static"); + } + } else if ((name_len == sizeof(ZEND_CONCAT_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CONCAT_FUNC_NAME, sizeof(ZEND_CONCAT_FUNC_NAME)-1))) { + if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { + zend_error(E_WARNING, "The magic method " ZEND_CONCAT_FUNC_NAME " must have public visibility and cannot be static"); } } } else { @@ -1335,6 +1339,11 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n zend_error(E_WARNING, "The magic method __toString() must have public visibility and cannot be static"); } CG(active_class_entry)->__tostring = (zend_function *) CG(active_op_array); + } else if ((name_len == sizeof(ZEND_CONCAT_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CONCAT_FUNC_NAME, sizeof(ZEND_CONCAT_FUNC_NAME)-1))) { + if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { + zend_error(E_WARNING, "The magic method " ZEND_CONCAT_FUNC_NAME " must have public visibility and cannot be static"); + } + CG(active_class_entry)->__concat = (zend_function *) CG(active_op_array); } else if (!(fn_flags & ZEND_ACC_STATIC)) { CG(active_op_array)->fn_flags |= ZEND_ACC_ALLOW_STATIC; } diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index faff1ec..0656883 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -745,6 +745,7 @@ END_EXTERN_C() #define ZEND_CALLSTATIC_FUNC_NAME "__callstatic" #define ZEND_TOSTRING_FUNC_NAME "__tostring" #define ZEND_AUTOLOAD_FUNC_NAME "__autoload" +#define ZEND_CONCAT_FUNC_NAME "__concat" /* The following constants may be combined in CG(compiler_options) * to change the default compiler behavior */ diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 1424a11..29a5ca1 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -1290,6 +1290,31 @@ ZEND_API int zend_std_cast_object_tostring(zval *readobj, zval *writeobj, int ty } /* }}} */ +ZEND_API int zend_std_concat_op(zval *obj, zval *result, zval *rhs TSRMLS_DC) /* {{{ */ +{ + zval *retval; + zend_class_entry *ce = Z_OBJCE_P(obj); + if (ce->__concat && (zend_call_method_with_1_params(&obj, ce, &ce->__concat, ZEND_CONCAT_FUNC_NAME, &retval, rhs) || EG(exception))) { + if (EG(exception)) { + if (retval) { + zval_ptr_dtor(&retval); + } + zend_error(E_ERROR, "Method %s::" ZEND_CONCAT_FUNC_NAME "() must not throw an exception", ce->name); + return FAILURE; + } + if (Z_TYPE_P(retval) == IS_NULL) { + zval_ptr_dtor(&retval); + return FAILURE; + } else { + ZVAL_ZVAL(result, retval, 1, 1); + return SUCCESS; + } + } + return FAILURE; +} +/* }}} */ + + int zend_std_get_closure(zval *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zval **zobj_ptr TSRMLS_DC) /* {{{ */ { zend_class_entry *ce; @@ -1344,6 +1369,7 @@ ZEND_API zend_object_handlers std_object_handlers = { NULL, /* count_elements */ NULL, /* get_debug_info */ zend_std_get_closure, /* get_closure */ + zend_std_concat_op /* concat_op */ }; /* diff --git a/Zend/zend_object_handlers.h b/Zend/zend_object_handlers.h index 34f4e02..5e73ef7 100644 --- a/Zend/zend_object_handlers.h +++ b/Zend/zend_object_handlers.h @@ -110,6 +110,8 @@ typedef int (*zend_object_count_elements_t)(zval *object, long *count TSRMLS_DC) typedef int (*zend_object_get_closure_t)(zval *obj, zend_class_entry **ce_ptr, union _zend_function **fptr_ptr, zval **zobj_ptr TSRMLS_DC); +typedef int (*zend_object_concat_op_t)(zval *obj, zval *result, zval *rhs TSRMLS_DC); + struct _zend_object_handlers { /* general object functions */ zend_object_add_ref_t add_ref; @@ -138,6 +140,7 @@ struct _zend_object_handlers { zend_object_count_elements_t count_elements; zend_object_get_debug_info_t get_debug_info; zend_object_get_closure_t get_closure; + zend_object_concat_op_t concat_op; }; extern ZEND_API zend_object_handlers std_object_handlers; @@ -151,6 +154,7 @@ ZEND_API struct _zend_property_info *zend_get_property_info(zend_class_entry *ce ZEND_API HashTable *zend_std_get_properties(zval *object TSRMLS_DC); ZEND_API HashTable *zend_std_get_debug_info(zval *object, int *is_temp TSRMLS_DC); ZEND_API int zend_std_cast_object_tostring(zval *readobj, zval *writeobj, int type TSRMLS_DC); +ZEND_API int zend_std_concat_op(zval *obj, zval *result, zval *rhs TSRMLS_DC); #define IS_ZEND_STD_OBJECT(z) (Z_TYPE(z) == IS_OBJECT && (Z_OBJ_HT((z))->get_class_entry != NULL)) diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index 8af1ede..154002c 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -1205,6 +1205,11 @@ ZEND_API int concat_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{ zval op1_copy, op2_copy; int use_copy1 = 0, use_copy2 = 0; + if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HT_P(op1)->concat_op) { + if (SUCCESS == Z_OBJ_HT_P(op1)->concat_op(op1, result, op2 TSRMLS_CC)) { + return SUCCESS; + } + } if (Z_TYPE_P(op1) != IS_STRING) { zend_make_printable_zval(op1, &op1_copy, &use_copy1); }