-
-
Save ircmaxell/1966809 to your computer and use it in GitHub Desktop.
| Index: Zend/zend.h | |
| =================================================================== | |
| --- Zend/zend.h (revision 323850) | |
| +++ Zend/zend.h (working copy) | |
| @@ -486,6 +486,10 @@ | |
| union _zend_function *__call; | |
| union _zend_function *__callstatic; | |
| union _zend_function *__tostring; | |
| + union _zend_function *__toint; | |
| + union _zend_function *__tofloat; | |
| + union _zend_function *__toarray; | |
| + union _zend_function *__toscalar; | |
| union _zend_function *serialize_func; | |
| union _zend_function *unserialize_func; | |
| Index: Zend/zend_object_handlers.c | |
| =================================================================== | |
| --- Zend/zend_object_handlers.c (revision 323850) | |
| +++ Zend/zend_object_handlers.c (working copy) | |
| @@ -1482,6 +1482,49 @@ | |
| } | |
| /* }}} */ | |
| +ZEND_API int zend_std_cast_object(zval *readobj, zval *writeobj, int type TSRMLS_DC) /* {{{ */ | |
| +{ | |
| + zend_class_entry *ce = Z_OBJCE_P(readobj); | |
| + zval *retval = NULL; | |
| + switch (type) { | |
| + case IS_LONG: | |
| + if (ce->__toint) { | |
| + zend_call_method_with_0_params(&readobj, ce, &ce->__toint, "__toint", &retval); | |
| + } | |
| + break; | |
| + case IS_DOUBLE: | |
| + if (ce->__tofloat) { | |
| + zend_call_method_with_0_params(&readobj, ce, &ce->__tofloat, "__tofloat", &retval); | |
| + } | |
| + break; | |
| + case IS_ARRAY: | |
| + if (ce->__toarray) { | |
| + zend_call_method_with_0_params(&readobj, ce, &ce->__toarray, "__toarray", &retval); | |
| + } | |
| + break; | |
| + } | |
| + if (retval) { | |
| + ZVAL_ZVAL(writeobj, retval, 1, 1); | |
| + return SUCCESS; | |
| + } | |
| + return zend_std_cast_object_tostring(readobj, writeobj, type TSRMLS_CC); | |
| + | |
| +} | |
| +/* }}} */ | |
| + | |
| +ZEND_API zval *zend_std_cast_object_get(zval *readobj TSRMLS_DC) /* {{{ */ | |
| +{ | |
| + zval *retval; | |
| + zend_class_entry *ce = Z_OBJCE_P(readobj); | |
| + ALLOC_INIT_ZVAL(retval); | |
| + if (ce->__toscalar && zend_call_method_with_0_params(&readobj, ce, &ce->__toscalar, "__toscalar", &retval)) { | |
| + return retval; | |
| + } | |
| + ZVAL_NULL(retval); | |
| + return retval; | |
| +} | |
| +/* }}} */ | |
| + | |
| ZEND_API int zend_std_cast_object_tostring(zval *readobj, zval *writeobj, int type TSRMLS_DC) /* {{{ */ | |
| { | |
| zval *retval; | |
| @@ -1589,7 +1632,7 @@ | |
| zend_std_read_dimension, /* read_dimension */ | |
| zend_std_write_dimension, /* write_dimension */ | |
| zend_std_get_property_ptr_ptr, /* get_property_ptr_ptr */ | |
| - NULL, /* get */ | |
| + zend_std_cast_object_get, /* get */ | |
| NULL, /* set */ | |
| zend_std_has_property, /* has_property */ | |
| zend_std_unset_property, /* unset_property */ | |
| @@ -1602,7 +1645,7 @@ | |
| zend_std_object_get_class, /* get_class_entry */ | |
| zend_std_object_get_class_name, /* get_class_name */ | |
| zend_std_compare_objects, /* compare_objects */ | |
| - zend_std_cast_object_tostring, /* cast_object */ | |
| + zend_std_cast_object, /* cast_object */ | |
| NULL, /* count_elements */ | |
| NULL, /* get_debug_info */ | |
| zend_std_get_closure, /* get_closure */ | |
| Index: Zend/zend_compile.c | |
| =================================================================== | |
| --- Zend/zend_compile.c (revision 323850) | |
| +++ Zend/zend_compile.c (working copy) | |
| @@ -1617,6 +1617,22 @@ | |
| 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_TOINT_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_TOINT_FUNC_NAME, sizeof(ZEND_TOINT_FUNC_NAME)-1))) { | |
| + if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { | |
| + zend_error(E_WARNING, "The magic method __toInt() must have public visibility and cannot be static"); | |
| + } | |
| + } else if ((name_len == sizeof(ZEND_TOFLOAT_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_TOFLOAT_FUNC_NAME, sizeof(ZEND_TOFLOAT_FUNC_NAME)-1))) { | |
| + if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { | |
| + zend_error(E_WARNING, "The magic method __toFloat() must have public visibility and cannot be static"); | |
| + } | |
| + } else if ((name_len == sizeof(ZEND_TOARRAY_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_TOARRAY_FUNC_NAME, sizeof(ZEND_TOARRAY_FUNC_NAME)-1))) { | |
| + if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { | |
| + zend_error(E_WARNING, "The magic method __toArray() must have public visibility and cannot be static"); | |
| + } | |
| + } else if ((name_len == sizeof(ZEND_TOSCALAR_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_TOSCALAR_FUNC_NAME, sizeof(ZEND_TOSCALAR_FUNC_NAME)-1))) { | |
| + if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { | |
| + zend_error(E_WARNING, "The magic method __toScalar() must have public visibility and cannot be static"); | |
| + } | |
| } | |
| } else { | |
| char *class_lcname; | |
| @@ -1673,6 +1689,26 @@ | |
| 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_TOINT_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_TOINT_FUNC_NAME, sizeof(ZEND_TOINT_FUNC_NAME)-1))) { | |
| + if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { | |
| + zend_error(E_WARNING, "The magic method __toInt() must have public visibility and cannot be static"); | |
| + } | |
| + CG(active_class_entry)->__toint = (zend_function *) CG(active_op_array); | |
| + } else if ((name_len == sizeof(ZEND_TOFLOAT_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_TOFLOAT_FUNC_NAME, sizeof(ZEND_TOFLOAT_FUNC_NAME)-1))) { | |
| + if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { | |
| + zend_error(E_WARNING, "The magic method __toFloat() must have public visibility and cannot be static"); | |
| + } | |
| + CG(active_class_entry)->__tofloat = (zend_function *) CG(active_op_array); | |
| + } else if ((name_len == sizeof(ZEND_TOARRAY_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_TOARRAY_FUNC_NAME, sizeof(ZEND_TOARRAY_FUNC_NAME)-1))) { | |
| + if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { | |
| + zend_error(E_WARNING, "The magic method __toArray() must have public visibility and cannot be static"); | |
| + } | |
| + CG(active_class_entry)->__toarray = (zend_function *) CG(active_op_array); | |
| + } else if ((name_len == sizeof(ZEND_TOSCALAR_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_TOSCALAR_FUNC_NAME, sizeof(ZEND_TOSCALAR_FUNC_NAME)-1))) { | |
| + if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { | |
| + zend_error(E_WARNING, "The magic method __toScalar() must have public visibility and cannot be static"); | |
| + } | |
| + CG(active_class_entry)->__toscalar = (zend_function *) CG(active_op_array); | |
| } else if (!(fn_flags & ZEND_ACC_STATIC)) { | |
| CG(active_op_array)->fn_flags |= ZEND_ACC_ALLOW_STATIC; | |
| } | |
| @@ -2839,6 +2875,18 @@ | |
| if (!ce->__tostring) { | |
| ce->__tostring = ce->parent->__tostring; | |
| } | |
| + if (!ce->__toint) { | |
| + ce->__toint = ce->parent->__toint; | |
| + } | |
| + if (!ce->__tofloat) { | |
| + ce->__tofloat = ce->parent->__tofloat; | |
| + } | |
| + if (!ce->__toarray) { | |
| + ce->__toarray = ce->parent->__toarray; | |
| + } | |
| + if (!ce->__toscalar) { | |
| + ce->__toscalar = ce->parent->__toscalar; | |
| + } | |
| if (!ce->clone) { | |
| ce->clone = ce->parent->clone; | |
| } | |
| @@ -3734,6 +3782,14 @@ | |
| ce->__callstatic = fe; | |
| } else if (!strncmp(mname, ZEND_TOSTRING_FUNC_NAME, mname_len)) { | |
| ce->__tostring = fe; | |
| + } else if (!strncmp(mname, ZEND_TOINT_FUNC_NAME, mname_len)) { | |
| + ce->__toint = fe; | |
| + } else if (!strncmp(mname, ZEND_TOFLOAT_FUNC_NAME, mname_len)) { | |
| + ce->__tofloat = fe; | |
| + } else if (!strncmp(mname, ZEND_TOARRAY_FUNC_NAME, mname_len)) { | |
| + ce->__toarray = fe; | |
| + } else if (!strncmp(mname, ZEND_TOSCALAR_FUNC_NAME, mname_len)) { | |
| + ce->__toscalar = fe; | |
| } else if (ce->name_length + 1 == mname_len) { | |
| char *lowercase_name = emalloc(ce->name_length + 1); | |
| zend_str_tolower_copy(lowercase_name, ce->name, ce->name_length); | |
| @@ -6742,6 +6798,10 @@ | |
| ce->__call = NULL; | |
| ce->__callstatic = NULL; | |
| ce->__tostring = NULL; | |
| + ce->__toint = NULL; | |
| + ce->__tofloat = NULL; | |
| + ce->__toarray = NULL; | |
| + ce->__toscalar = NULL; | |
| ce->create_object = NULL; | |
| ce->get_iterator = NULL; | |
| ce->iterator_funcs.funcs = NULL; | |
| Index: Zend/zend_object_handlers.h | |
| =================================================================== | |
| --- Zend/zend_object_handlers.h (revision 323850) | |
| +++ Zend/zend_object_handlers.h (working copy) | |
| @@ -154,6 +154,8 @@ | |
| ZEND_API struct _zend_property_info *zend_get_property_info(zend_class_entry *ce, zval *member, int silent TSRMLS_DC); | |
| 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 zval *zend_std_cast_object_get(zval *readobj TSRMLS_DC); | |
| +ZEND_API int zend_std_cast_object(zval *readobj, zval *writeobj, int type TSRMLS_DC); | |
| ZEND_API int zend_std_cast_object_tostring(zval *readobj, zval *writeobj, int type TSRMLS_DC); | |
| ZEND_API void zend_std_write_property(zval *object, zval *member, zval *value, const struct _zend_literal *key TSRMLS_DC); | |
| ZEND_API void rebuild_object_properties(zend_object *zobj); | |
| Index: Zend/zend_compile.h | |
| =================================================================== | |
| --- Zend/zend_compile.h (revision 323850) | |
| +++ Zend/zend_compile.h (working copy) | |
| @@ -829,6 +829,10 @@ | |
| #define ZEND_CALL_FUNC_NAME "__call" | |
| #define ZEND_CALLSTATIC_FUNC_NAME "__callstatic" | |
| #define ZEND_TOSTRING_FUNC_NAME "__tostring" | |
| +#define ZEND_TOINT_FUNC_NAME "__toint" | |
| +#define ZEND_TOFLOAT_FUNC_NAME "__tofloat" | |
| +#define ZEND_TOARRAY_FUNC_NAME "__toarray" | |
| +#define ZEND_TOSCALAR_FUNC_NAME "__toscalar" | |
| #define ZEND_AUTOLOAD_FUNC_NAME "__autoload" | |
| /* The following constants may be combined in CG(compiler_options) | |
| Index: Zend/zend_API.c | |
| =================================================================== | |
| --- Zend/zend_API.c (revision 323850) | |
| +++ Zend/zend_API.c (working copy) | |
| @@ -27,6 +27,7 @@ | |
| #include "zend_constants.h" | |
| #include "zend_exceptions.h" | |
| #include "zend_closures.h" | |
| +#include "zend_interfaces.h" | |
| #ifdef HAVE_STDARG_H | |
| #include <stdarg.h> | |
| @@ -368,9 +369,25 @@ | |
| convert_to_long_ex(arg); | |
| *p = Z_LVAL_PP(arg); | |
| break; | |
| - | |
| + case IS_OBJECT: | |
| + { | |
| + zend_class_entry *ce = Z_OBJCE_PP(arg); | |
| + zval *tmp = NULL; | |
| + if (ce->__toint) { | |
| + if (Z_ISREF_PP(arg)) { | |
| + zend_spprintf(error, 0, "to be an int, cannot cast referenced parameter from object"); | |
| + return "long"; | |
| + } | |
| + zend_call_method_with_0_params(arg, ce, &ce->__toint, "__toint", &tmp); | |
| + if (tmp && Z_TYPE_P(tmp) == IS_LONG) { | |
| + *p = Z_LVAL_P(tmp); | |
| + zval_ptr_dtor(&tmp); | |
| + break; | |
| + } | |
| + } | |
| + } | |
| + /* Fall through intentional */ | |
| case IS_ARRAY: | |
| - case IS_OBJECT: | |
| case IS_RESOURCE: | |
| default: | |
| return "long"; | |
| @@ -402,9 +419,25 @@ | |
| convert_to_double_ex(arg); | |
| *p = Z_DVAL_PP(arg); | |
| break; | |
| - | |
| + case IS_OBJECT: | |
| + { | |
| + zend_class_entry *ce = Z_OBJCE_PP(arg); | |
| + zval *tmp = NULL; | |
| + if (ce->__tofloat) { | |
| + if (Z_ISREF_PP(arg)) { | |
| + zend_spprintf(error, 0, "to be a float, cannot cast referenced parameter from object"); | |
| + return "double"; | |
| + } | |
| + zend_call_method_with_0_params(arg, ce, &ce->__tofloat, "__tofloat", &tmp); | |
| + if (tmp && Z_TYPE_P(tmp) == IS_DOUBLE) { | |
| + *p = Z_DVAL_P(tmp); | |
| + zval_ptr_dtor(&tmp); | |
| + break; | |
| + } | |
| + } | |
| + } | |
| + /* Fall through intentional */ | |
| case IS_ARRAY: | |
| - case IS_OBJECT: | |
| case IS_RESOURCE: | |
| default: | |
| return "double"; | |
| @@ -506,6 +539,23 @@ | |
| } | |
| if (Z_TYPE_PP(arg) == IS_ARRAY || (c == 'A' && Z_TYPE_PP(arg) == IS_OBJECT)) { | |
| *p = *arg; | |
| + } else if (Z_TYPE_PP(arg) == IS_OBJECT) { | |
| + zend_class_entry *ce = Z_OBJCE_PP(arg); | |
| + zval *tmp = NULL; | |
| + if (ce->__toarray) { | |
| + if (Z_ISREF_PP(arg)) { | |
| + zend_spprintf(error, 0, "to be an array, cannot cast referenced parameter from object"); | |
| + return "array"; | |
| + } | |
| + zend_call_method_with_0_params(arg, ce, &ce->__toarray, "__toarray", &tmp); | |
| + if (tmp && Z_TYPE_P(tmp) == IS_ARRAY) { | |
| + SEPARATE_ZVAL_IF_NOT_REF(arg); | |
| + ZVAL_ZVAL(*arg, tmp, 1, 1) ; | |
| + *p = *arg; | |
| + break; | |
| + } | |
| + } | |
| + return "array"; | |
| } else { | |
| return "array"; | |
| } | |
| @@ -526,6 +576,19 @@ | |
| if(*p == NULL) { | |
| return "array"; | |
| } | |
| + } else if (Z_TYPE_PP(arg) == IS_OBJECT) { | |
| + zend_class_entry *ce = Z_OBJCE_PP(arg); | |
| + zval *tmp = NULL; | |
| + if (ce->__toarray) { | |
| + zend_call_method_with_0_params(arg, ce, &ce->__toarray, "__toarray", &tmp); | |
| + if (tmp && Z_TYPE_P(tmp) == IS_ARRAY) { | |
| + SEPARATE_ZVAL_IF_NOT_REF(arg); | |
| + ZVAL_ZVAL(*arg, tmp, 1, 1); | |
| + *p = HASH_OF(*arg); | |
| + break; | |
| + } | |
| + } | |
| + return "array"; | |
| } else { | |
| return "array"; | |
| } | |
| @@ -1930,7 +1993,7 @@ | |
| int count=0, unload=0, result=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, *__toint = NULL, *__tofloat = NULL, *__toarray = NULL, *__toscalar = NULL; | |
| const char *lowercase_name; | |
| int fname_len; | |
| const char *lc_class_name = NULL; | |
| @@ -2065,6 +2128,14 @@ | |
| __callstatic = reg_function; | |
| } else if ((fname_len == sizeof(ZEND_TOSTRING_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_TOSTRING_FUNC_NAME, sizeof(ZEND_TOSTRING_FUNC_NAME))) { | |
| __tostring = reg_function; | |
| + } else if ((fname_len == sizeof(ZEND_TOINT_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_TOINT_FUNC_NAME, sizeof(ZEND_TOINT_FUNC_NAME))) { | |
| + __toint = reg_function; | |
| + } else if ((fname_len == sizeof(ZEND_TOFLOAT_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_TOFLOAT_FUNC_NAME, sizeof(ZEND_TOFLOAT_FUNC_NAME))) { | |
| + __tofloat = reg_function; | |
| + } else if ((fname_len == sizeof(ZEND_TOARRAY_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_TOARRAY_FUNC_NAME, sizeof(ZEND_TOARRAY_FUNC_NAME))) { | |
| + __toarray = reg_function; | |
| + } else if ((fname_len == sizeof(ZEND_TOSCALAR_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_TOSCALAR_FUNC_NAME, sizeof(ZEND_TOSCALAR_FUNC_NAME))) { | |
| + __toscalar = reg_function; | |
| } else if ((fname_len == sizeof(ZEND_GET_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME))) { | |
| __get = reg_function; | |
| } else if ((fname_len == sizeof(ZEND_SET_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME))) { | |
| @@ -2107,6 +2178,10 @@ | |
| scope->__call = __call; | |
| scope->__callstatic = __callstatic; | |
| scope->__tostring = __tostring; | |
| + scope->__toint = __toint; | |
| + scope->__tofloat = __tofloat; | |
| + scope->__toarray = __toarray; | |
| + scope->__toscalar = __toscalar; | |
| scope->__get = __get; | |
| scope->__set = __set; | |
| scope->__unset = __unset; | |
| @@ -2150,6 +2225,30 @@ | |
| } | |
| __tostring->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC; | |
| } | |
| + if (__toint) { | |
| + if (__toint->common.fn_flags & ZEND_ACC_STATIC) { | |
| + zend_error(error_type, "Method %s::%s() cannot be static", scope->name, __toint->common.function_name); | |
| + } | |
| + __toint->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC; | |
| + } | |
| + if (__tofloat) { | |
| + if (__tofloat->common.fn_flags & ZEND_ACC_STATIC) { | |
| + zend_error(error_type, "Method %s::%s() cannot be static", scope->name, __tofloat->common.function_name); | |
| + } | |
| + __tofloat->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC; | |
| + } | |
| + if (__toarray) { | |
| + if (__toarray->common.fn_flags & ZEND_ACC_STATIC) { | |
| + zend_error(error_type, "Method %s::%s() cannot be static", scope->name, __toarray->common.function_name); | |
| + } | |
| + __toarray->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC; | |
| + } | |
| + if (__toscalar) { | |
| + if (__toscalar->common.fn_flags & ZEND_ACC_STATIC) { | |
| + zend_error(error_type, "Method %s::%s() cannot be static", scope->name, __toscalar->common.function_name); | |
| + } | |
| + __toscalar->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC; | |
| + } | |
| if (__get) { | |
| if (__get->common.fn_flags & ZEND_ACC_STATIC) { | |
| zend_error(error_type, "Method %s::%s() cannot be static", scope->name, __get->common.function_name); | |
| Index: Zend/zend_operators.c | |
| =================================================================== | |
| --- Zend/zend_operators.c (revision 323850) | |
| +++ Zend/zend_operators.c (working copy) | |
| @@ -30,6 +30,7 @@ | |
| #include "zend_strtod.h" | |
| #include "zend_exceptions.h" | |
| #include "zend_closures.h" | |
| +#include "zend_interfaces.h" | |
| #if ZEND_USE_TOLOWER_L | |
| #include <locale.h> | |
| @@ -640,6 +641,7 @@ | |
| case IS_OBJECT: | |
| { | |
| zval *tmp; | |
| + zend_class_entry *ce = Z_OBJCE_P(op); | |
| HashTable *ht; | |
| ALLOC_HASHTABLE(ht); | |
| @@ -651,6 +653,15 @@ | |
| FREE_HASHTABLE(ht); | |
| return; | |
| } | |
| + } else if (ce->__toarray) { | |
| + zend_call_method_with_0_params(&op, ce, &ce->__toarray, "__toarray", &tmp); | |
| + if (tmp && Z_TYPE_P(tmp) == IS_ARRAY) { | |
| + ZVAL_ZVAL(op, tmp, 1, 1); | |
| + zend_hash_destroy(ht); | |
| + FREE_HASHTABLE(ht); | |
| + return; | |
| + } | |
| + zend_error(E_WARNING, "%s::__toArray() must return an array", ce->name); | |
| } else if (Z_OBJ_HT_P(op)->get_properties) { | |
| HashTable *obj_ht = Z_OBJ_HT_P(op)->get_properties(op TSRMLS_CC); | |
| if (obj_ht) { | |
| Index: Zend/zend_API.h | |
| =================================================================== | |
| --- Zend/zend_API.h (revision 323850) | |
| +++ Zend/zend_API.h (working copy) | |
| @@ -186,6 +186,10 @@ | |
| class_container.__call = handle_fcall; \ | |
| class_container.__callstatic = NULL; \ | |
| class_container.__tostring = NULL; \ | |
| + class_container.__toint = NULL; \ | |
| + class_container.__tofloat = NULL; \ | |
| + class_container.__toarray = NULL; \ | |
| + class_container.__toscalar = NULL; \ | |
| class_container.__get = handle_propget; \ | |
| class_container.__set = handle_propset; \ | |
| class_container.__unset = handle_propunset; \ |
@rmccue: There are more than that, there's actually a number of white-space issues (I'm attributing it to the editor I used over the terminal which converts tabs to spaces in some cases). The final patch will clean up the whitespace significantly.
Thanks for the comment
Anthony
What about a __toBool (or __toBoolean) magic method? This would be useful for quick object comparisons without an additional method call, like:
if($obj) {
// success
} else {
// errors
}
Here is another good reason why this patch should be considered http://stackoverflow.com/questions/16375331/increment-on-tostring .... +1 @ircmaxwell
Hi there. I found your patch on the php rfc site. I wrote you an email a while back, don't know if you got it or not, but it basically discussed a bug/issue that I found with your patch. More specifically, there's an issue with implicit casts not working when performing arith. operations on objects, where the __toScalar function should be called but it never is. Let me know if you got my message, and, if not, i can just fill you in on the details either here or via email.
@ircmaxwell Why did not this happen?
I'm interested in this as well.
+1
Cool for now, but i'm also interested in __toBool and a __toClass or __toObject magic to perform object-to-object casts, something like:
class A {
public $test = '';
public __construct($test) {
$this->test = $test;
}
function someFunction() {
echo $this->test;
}
}
class B {
protected $test = '123';
function __toObject($class) {
// it is possible to convert to A
if ($class == 'A') {
return new A($this->test, $this);
}
// throw an error
}
}
$b = new $B;
$a = (A) $b;
echo $a->test; // should be 123
$x = ((A) $b)->someFunction(); // should also be 123Same should be possible for parameters in functions/methods like:
public function _(Photo $i) // Implies that $i must be object of class Photo
public function _((Photo) $i) // Implies that $i can be converted to an Photo and must therefor be convertableI think much more sexy is using angle brackets, in my opinien... See:
$a = <A> $b;
$x = (<A> $b)->someFunction();
public function _(<Photo> $i);I'm interested in this too. I think it is the perfect moment for this to be included in PHP core.
Why would you choose a separate function for each class instead of a more general __toType(string $type)?
Please release.
When doing $obj + 123, $obj shouldn't be treated as a string. Adding __toscalar is handy for solving this.
I created php/php-src#14073
Please vote.
Side note:
#define ZEND_TOINT_FUNC_NAME "__toint"(etc) uses tabs for alignment, the other lines use spaces, so with a different tab width, these don't line up.