diff -rU3 php-5.2.6-orig/Zend/zend_API.c php-5.2.6/Zend/zend_API.c --- php-5.2.6-orig/Zend/zend_API.c 2008-03-06 18:28:47.000000000 +0100 +++ php-5.2.6/Zend/zend_API.c 2008-10-06 05:39:11.731658147 +0200 @@ -1641,7 +1641,7 @@ 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, *__tostring = NULL; + zend_function *ctor = NULL, *dtor = NULL, *clone = NULL, *__get = NULL, *__set = NULL, *__unset = NULL, *__isset = NULL, *__call = NULL, *__tostring = NULL, *__cast = NULL; char *lowercase_name; int fname_len; char *lc_class_name = NULL; @@ -1755,6 +1755,8 @@ __call = 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_CAST_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_CAST_FUNC_NAME, sizeof(ZEND_CAST_FUNC_NAME))) { + __cast = 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))) { @@ -1793,6 +1795,7 @@ scope->clone = clone; scope->__call = __call; scope->__tostring = __tostring; + scope->__cast = __cast; scope->__get = __get; scope->__set = __set; scope->__unset = __unset; @@ -1830,6 +1833,12 @@ } __tostring->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC; } + if (__cast) { + if (__cast->common.fn_flags & ZEND_ACC_STATIC) { + zend_error(error_type, "Method %s::%s() cannot be static", scope->name, __cast->common.function_name); + } + __cast->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); diff -rU3 php-5.2.6-orig/Zend/zend_API.h php-5.2.6/Zend/zend_API.h --- php-5.2.6-orig/Zend/zend_API.h 2007-12-31 08:20:02.000000000 +0100 +++ php-5.2.6/Zend/zend_API.h 2008-10-05 19:27:39.081760977 +0200 @@ -140,6 +140,7 @@ class_container.interface_gets_implemented = NULL; \ class_container.__call = handle_fcall; \ class_container.__tostring = NULL; \ + class_container.__cast = NULL; \ class_container.__get = handle_propget; \ class_container.__set = handle_propset; \ class_container.__unset = handle_propunset; \ diff -rU3 php-5.2.6-orig/Zend/zend_compile.c php-5.2.6/Zend/zend_compile.c --- php-5.2.6-orig/Zend/zend_compile.c 2008-02-20 13:04:49.000000000 +0100 +++ php-5.2.6/Zend/zend_compile.c 2008-10-06 05:51:42.390408098 +0200 @@ -1198,6 +1198,8 @@ CG(active_class_entry)->__isset = (zend_function *) CG(active_op_array); } else if ((name_len == sizeof(ZEND_TOSTRING_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_TOSTRING_FUNC_NAME, sizeof(ZEND_TOSTRING_FUNC_NAME)))) { CG(active_class_entry)->__tostring = (zend_function *) CG(active_op_array); + } else if ((name_len == sizeof(ZEND_CAST_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CAST_FUNC_NAME, sizeof(ZEND_CAST_FUNC_NAME)))) { + CG(active_class_entry)->__cast = (zend_function *) CG(active_op_array); } else if (!(fn_flags & ZEND_ACC_STATIC)) { CG(active_op_array)->fn_flags |= ZEND_ACC_ALLOW_STATIC; } @@ -1919,6 +1921,9 @@ if (!ce->__tostring) { ce->__tostring = ce->parent->__tostring; } + if (!ce->__cast) { + ce->__cast = ce->parent->__cast; + } if (!ce->clone) { ce->clone = ce->parent->clone; } @@ -4234,6 +4239,7 @@ ce->__isset = NULL; ce->__call = NULL; ce->__tostring = NULL; + ce->__cast = NULL; ce->create_object = NULL; ce->get_iterator = NULL; ce->iterator_funcs.funcs = NULL; diff -rU3 php-5.2.6-orig/Zend/zend_compile.h php-5.2.6/Zend/zend_compile.h --- php-5.2.6-orig/Zend/zend_compile.h 2007-12-31 08:20:02.000000000 +0100 +++ php-5.2.6/Zend/zend_compile.h 2008-10-05 19:27:39.261735162 +0200 @@ -697,6 +697,7 @@ #define ZEND_ISSET_FUNC_NAME "__isset" #define ZEND_CALL_FUNC_NAME "__call" #define ZEND_TOSTRING_FUNC_NAME "__tostring" +#define ZEND_CAST_FUNC_NAME "__cast" #define ZEND_AUTOLOAD_FUNC_NAME "__autoload" #endif /* ZEND_COMPILE_H */ diff -rU3 php-5.2.6-orig/Zend/zend.h php-5.2.6/Zend/zend.h --- php-5.2.6-orig/Zend/zend.h 2008-02-15 08:44:45.000000000 +0100 +++ php-5.2.6/Zend/zend.h 2008-10-05 19:27:39.361719912 +0200 @@ -353,6 +353,7 @@ union _zend_function *__isset; union _zend_function *__call; union _zend_function *__tostring; + union _zend_function *__cast; union _zend_function *serialize_func; union _zend_function *unserialize_func; diff -rU3 php-5.2.6-orig/Zend/zend_object_handlers.c php-5.2.6/Zend/zend_object_handlers.c --- php-5.2.6-orig/Zend/zend_object_handlers.c 2008-02-21 14:55:22.000000000 +0100 +++ php-5.2.6/Zend/zend_object_handlers.c 2008-10-06 06:05:09.810415748 +0200 @@ -1092,9 +1092,60 @@ zval *retval; zend_class_entry *ce; + ce = Z_OBJCE_P(readobj); + + if (ce->__cast) { + // HANDLE __cast($type) + zval type_str; + char *type_c_str = "unknown"; + + switch(type) { + case IS_STRING: type_c_str = "string"; break; + case IS_BOOL: type_c_str = "bool"; break; + case IS_LONG: type_c_str = "int"; break; + case IS_DOUBLE: type_c_str = "float"; break; + } + + ZVAL_STRING(&type_str, type_c_str, 0); + // Avoid stupid php 5.2.6 try to free our string + ZVAL_ADDREF(&type_str); + + if ((zend_call_method_with_1_params(&readobj, ce, &ce->__cast, "__cast", &retval, &type_str)) || EG(exception)) { + if (EG(exception)) { + if (retval) { + zval_ptr_dtor(&retval); + retval = NULL; + } + + zend_error(E_ERROR, "Method %s::__cast() must not throw an exception", ce->name); + return FAILURE; + } + if (Z_TYPE_P(retval) == type) { + INIT_PZVAL(writeobj); + if (readobj == writeobj) { + zval_dtor(readobj); + } + ZVAL_ZVAL(writeobj, retval, 1, 1); + if (Z_TYPE_P(writeobj) != type) { + convert_to_explicit_type(writeobj, type); + } + return SUCCESS; + } else { + zval_ptr_dtor(&retval); + INIT_PZVAL(writeobj); + if (readobj == writeobj) { + zval_dtor(readobj); + } + ZVAL_EMPTY_STRING(writeobj); + zend_error(E_RECOVERABLE_ERROR, "Method %s::__cast() must return the requested type of value", ce->name); + return SUCCESS; + } + } + } + switch (type) { case IS_STRING: - ce = Z_OBJCE_P(readobj); +// ce = Z_OBJCE_P(readobj); if (ce->__tostring && (zend_call_method_with_0_params(&readobj, ce, &ce->__tostring, "__tostring", &retval) || EG(exception))) { if (EG(exception)) {