]> granicus.if.org Git - php/commitdiff
- Have __toString() be called if available in all places an object is used
authorMarcus Boerger <helly@php.net>
Wed, 5 Oct 2005 19:02:27 +0000 (19:02 +0000)
committerMarcus Boerger <helly@php.net>
Wed, 5 Oct 2005 19:02:27 +0000 (19:02 +0000)
  as a string.
#
# Note that "Object #<id>" is no longer afallback for debugging purpose use
# var_dump, which was made for debugging. If you used this to grab the id
# of an object you can never rely on this. For object storage look at SPL's
# ObjectStorage class.
#
# Note the signature change in the cast handler:
#
# int (*cast_t)(zval *readobj, zval *writeobj, int type, int should_free TSRMLS_DC);
# int (*cast_t)(zval *readobj, zval *retval, int type TSRMLS_DC);

Zend/zend.c
Zend/zend_API.c
Zend/zend_execute.h
Zend/zend_object_handlers.c
Zend/zend_object_handlers.h
Zend/zend_operators.c

index 37108066ac281a870449d5a7ce2a091c6ffa4676..8cafecfdc57c468020b66ba7006c3923e424764d 100644 (file)
@@ -347,29 +347,22 @@ ZEND_API void zend_make_string_zval(zval *expr, zval *expr_copy, int *use_copy)
                case IS_OBJECT:
                        {
                                TSRMLS_FETCH();
-                               if (Z_OBJ_HANDLER_P(expr, cast_object)) {
-                                       if(Z_OBJ_HANDLER_P(expr, cast_object)(expr, expr_copy, IS_STRING, 0 TSRMLS_CC) == SUCCESS) {
-                                               break;
-                                       }
+
+                               if(Z_OBJ_HT_P(expr)->cast_object && Z_OBJ_HANDLER_P(expr, cast_object)(expr, expr_copy, IS_STRING TSRMLS_CC) == SUCCESS) {
+                                       break;
                                }
                                if (Z_OBJ_HANDLER_P(expr, get)) {
                                        zval *z = Z_OBJ_HANDLER_P(expr, get)(expr TSRMLS_CC);
                                        if(Z_TYPE_P(z) != IS_OBJECT) {
-                                               zend_make_printable_zval(z, expr_copy, use_copy);
+                                               zend_make_string_zval(z, expr_copy, use_copy);
                                                FREE_ZVAL(z);
                                                break;
                                        }
                                }
-                               if (EG(exception)) {
-                                       expr_copy->value.str.len = 0;
-                                       expr_copy->value.str.val = STR_EMPTY_ALLOC();
-                                       break;
-                               }
-
+                               zend_error(EG(exception) ? E_ERROR : E_RECOVERABLE_ERROR, "Object of class %v could not be converted to string", Z_OBJCE_P(expr)->name);
+                               ZVAL_EMPTY_STRING(expr_copy);
+                               break;
                        }
-                       expr_copy->value.str.val = (char *) emalloc(sizeof("Object id #")-1 + MAX_LENGTH_OF_LONG);
-                       expr_copy->value.str.len = sprintf(expr_copy->value.str.val, "Object id #%ld", (long)expr->value.obj.handle);
-                       break;
                default:
                        *expr_copy = *expr;
                        zval_copy_ctor(expr_copy);
@@ -416,10 +409,8 @@ ZEND_API void zend_make_printable_zval(zval *expr, zval *expr_copy, int *use_cop
                        expr_copy->value.str.val = estrndup("Array", expr_copy->value.str.len);
                        break;
                case IS_OBJECT:
-                       if (Z_OBJ_HANDLER_P(expr, cast_object)) {
-                               if(Z_OBJ_HANDLER_P(expr, cast_object)(expr, expr_copy, IS_STRING, 0 TSRMLS_CC) == SUCCESS) {
-                                       break;
-                               }
+                       if(Z_OBJ_HT_P(expr)->cast_object && Z_OBJ_HANDLER_P(expr, cast_object)(expr, expr_copy, IS_STRING TSRMLS_CC) == SUCCESS) {
+                               break;
                        }
                        if (Z_OBJ_HANDLER_P(expr, get)) {
                                zval *z = Z_OBJ_HANDLER_P(expr, get)(expr TSRMLS_CC);
@@ -429,13 +420,8 @@ ZEND_API void zend_make_printable_zval(zval *expr, zval *expr_copy, int *use_cop
                                        break;
                                }
                        }
-                       if (EG(exception)) {
-                               expr_copy->value.str.len = 0;
-                               expr_copy->value.str.val = STR_EMPTY_ALLOC();
-                               break;
-                       }
-                       expr_copy->value.str.val = (char *) emalloc(sizeof("Object id #")-1 + MAX_LENGTH_OF_LONG);
-                       expr_copy->value.str.len = sprintf(expr_copy->value.str.val, "Object id #%ld", (long)expr->value.obj.handle);
+                       zend_error(EG(exception) ? E_ERROR : E_RECOVERABLE_ERROR, "Object of class %v could not be converted to string", Z_OBJCE_P(expr)->name);
+                       ZVAL_EMPTY_STRING(expr_copy);
                        break;
                case IS_DOUBLE:
                        *expr_copy = *expr;
@@ -467,10 +453,8 @@ ZEND_API void zend_make_unicode_zval(zval *expr, zval *expr_copy, int *use_copy)
        }
        switch (expr->type) {
                case IS_OBJECT:
-                       if (Z_OBJ_HANDLER_P(expr, cast_object)) {
-                               if(Z_OBJ_HANDLER_P(expr, cast_object)(expr, expr_copy, IS_UNICODE, 0 TSRMLS_CC) == SUCCESS) {
-                                       break;
-                               }
+                       if(Z_OBJ_HT_P(expr)->cast_object && Z_OBJ_HANDLER_P(expr, cast_object)(expr, expr_copy, IS_UNICODE TSRMLS_CC) == SUCCESS) {
+                               break;
                        }
                        if (Z_OBJ_HANDLER_P(expr, get)) {
                                zval *z = Z_OBJ_HANDLER_P(expr, get)(expr TSRMLS_CC);
@@ -480,13 +464,8 @@ ZEND_API void zend_make_unicode_zval(zval *expr, zval *expr_copy, int *use_copy)
                                        break;
                                }
                        }
-                       if (EG(exception)) {
-                               expr_copy->value.ustr.len = 0;
-                               expr_copy->value.ustr.val = USTR_MAKE("");
-                               break;
-                       }
-                       expr_copy->value.ustr.val = eumalloc(sizeof("Object id #")-1 + MAX_LENGTH_OF_LONG + 1);
-                       expr_copy->value.ustr.len = u_sprintf(expr_copy->value.ustr.val, "Object id #%ld", (long)expr->value.obj.handle);
+                       zend_error(EG(exception) ? E_ERROR : E_RECOVERABLE_ERROR, "Object of class %v could not be converted to string", Z_OBJCE_P(expr)->name);
+                       ZVAL_EMPTY_STRING(expr_copy);
                        break;
                default:
                        *expr_copy = *expr;
index 3cf8481dbd68ebc5bda851d30c4c9f192bf0397c..6a34911fcee41b69c8f8878efab01ace292e38fb 100644 (file)
@@ -432,7 +432,7 @@ static char *zend_parse_arg_impl(zval **arg, va_list *va, char **spec, char T_ar
                                        case IS_OBJECT: {
                                                if (Z_OBJ_HANDLER_PP(arg, cast_object)) {
                                                        SEPARATE_ZVAL_IF_NOT_REF(arg);
-                                                       if (Z_OBJ_HANDLER_PP(arg, cast_object)(*arg, *arg, IS_STRING, 0 TSRMLS_CC) == SUCCESS) {
+                                                       if (Z_OBJ_HANDLER_PP(arg, cast_object)(*arg, *arg, IS_STRING TSRMLS_CC) == SUCCESS) {
                                                                *pl = Z_STRLEN_PP(arg);
                                                                *p = Z_STRVAL_PP(arg);
                                                                break;
@@ -481,7 +481,7 @@ static char *zend_parse_arg_impl(zval **arg, va_list *va, char **spec, char T_ar
                                        case IS_OBJECT: {
                                                if (Z_OBJ_HANDLER_PP(arg, cast_object)) {
                                                        SEPARATE_ZVAL_IF_NOT_REF(arg);
-                                                       if (Z_OBJ_HANDLER_PP(arg, cast_object)(*arg, *arg, IS_BINARY, 0 TSRMLS_CC) == SUCCESS) {
+                                                       if (Z_OBJ_HANDLER_PP(arg, cast_object)(*arg, *arg, IS_BINARY TSRMLS_CC) == SUCCESS) {
                                                                *pl = Z_BINLEN_PP(arg);
                                                                *p = Z_BINVAL_PP(arg);
                                                                break;
@@ -525,7 +525,7 @@ static char *zend_parse_arg_impl(zval **arg, va_list *va, char **spec, char T_ar
                                        case IS_OBJECT: {
                                                if (Z_OBJ_HANDLER_PP(arg, cast_object)) {
                                                        SEPARATE_ZVAL_IF_NOT_REF(arg);
-                                                       if (Z_OBJ_HANDLER_PP(arg, cast_object)(*arg, *arg, IS_UNICODE, 0 TSRMLS_CC) == SUCCESS) {
+                                                       if (Z_OBJ_HANDLER_PP(arg, cast_object)(*arg, *arg, IS_UNICODE TSRMLS_CC) == SUCCESS) {
                                                                *pl = Z_USTRLEN_PP(arg);
                                                                *p = Z_USTRVAL_PP(arg);
                                                                break;
@@ -588,7 +588,7 @@ static char *zend_parse_arg_impl(zval **arg, va_list *va, char **spec, char T_ar
                                        case IS_OBJECT: {
                                                if (Z_OBJ_HANDLER_PP(arg, cast_object)) {
                                                        SEPARATE_ZVAL_IF_NOT_REF(arg);
-                                                       if (Z_OBJ_HANDLER_PP(arg, cast_object)(*arg, *arg, T_arg_type, 0 TSRMLS_CC) == SUCCESS) {
+                                                       if (Z_OBJ_HANDLER_PP(arg, cast_object)(*arg, *arg, T_arg_type TSRMLS_CC) == SUCCESS) {
                                                                *(char**)p = Z_UNIVAL_PP(arg);
                                                                *pl = Z_UNILEN_PP(arg);
                                                                *type = Z_TYPE_PP(arg);
@@ -651,12 +651,12 @@ static char *zend_parse_arg_impl(zval **arg, va_list *va, char **spec, char T_ar
                                                if (Z_OBJ_HANDLER_PP(arg, cast_object)) {
                                                        SEPARATE_ZVAL_IF_NOT_REF(arg);
                                                        if (UG(unicode)) {
-                                                               if (Z_OBJ_HANDLER_PP(arg, cast_object)(*arg, *arg, IS_UNICODE, 0 TSRMLS_CC) == SUCCESS) {
+                                                               if (Z_OBJ_HANDLER_PP(arg, cast_object)(*arg, *arg, IS_UNICODE TSRMLS_CC) == SUCCESS) {
                                                                        RETURN_AS_UNICODE(arg, p, pl, type);
                                                                        break;
                                                                }
                                                        } else {
-                                                               if (Z_OBJ_HANDLER_PP(arg, cast_object)(*arg, *arg, IS_STRING, 0 TSRMLS_CC) == SUCCESS) {
+                                                               if (Z_OBJ_HANDLER_PP(arg, cast_object)(*arg, *arg, IS_STRING TSRMLS_CC) == SUCCESS) {
                                                                        RETURN_AS_STRING(arg, p, pl, type);
                                                                        break;
                                                                }
index 7095ac1b155c7f35d653aef3af024bb44be08fa5..3096a2a38ee64315dc24a0d1c6ae2be3d3d256c3 100644 (file)
@@ -114,7 +114,7 @@ static inline int i_zend_is_true(zval *op)
 
                                if (Z_OBJ_HT_P(op)->cast_object) {
                                        zval tmp;
-                                       if (Z_OBJ_HT_P(op)->cast_object(op, &tmp, IS_BOOL, 0 TSRMLS_CC) == SUCCESS) {
+                                       if (Z_OBJ_HT_P(op)->cast_object(op, &tmp, IS_BOOL TSRMLS_CC) == SUCCESS) {
                                                result = Z_LVAL(tmp);
                                                break;
                                        }
index de0d27213dd08470ffbbb675b872601faf6c5af4..52cad9c7ef62052c27ad24e5c6984038397179dc 100644 (file)
@@ -1006,29 +1006,35 @@ int zend_std_object_get_class_name(zval *object, char **class_name, zend_uint *c
        return SUCCESS;
 }
 
-ZEND_API int zend_std_cast_object_tostring(zval *readobj, zval *writeobj, int type, int should_free TSRMLS_DC)
+ZEND_API int zend_std_cast_object_tostring(zval *readobj, zval *writeobj, int type TSRMLS_DC)
 {
        zval *retval;
        zend_class_entry *ce;
-       
+
        switch (type) {
                case IS_STRING:
                case IS_UNICODE:
                        ce = Z_OBJCE_P(readobj);
                        if (ce->__tostring &&
                 zend_call_method_with_0_params(&readobj, ce, &ce->__tostring, "__tostring", &retval)) {
+                if (EG(exception)) {
+                       zval_ptr_dtor(&retval);
+                                       zend_error(E_ERROR, "Method %v::__toString() must not throw an exception", ce->name);
+                       return FAILURE;
+                }
                                if (Z_TYPE_P(retval) == (UG(unicode)?IS_UNICODE:IS_STRING)) {
-                                       *writeobj = *retval;
-                                       zval_copy_ctor(writeobj);
-                                       zval_ptr_dtor(&retval);
                                        INIT_PZVAL(writeobj);
+                                       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);
+                                       ZVAL_EMPTY_STRING(writeobj);
                                        zend_error(E_RECOVERABLE_ERROR, "Method %v::__toString() must return a string value", ce->name);
+                                       return SUCCESS;
                                }
                        }
                        return FAILURE;
index 3ed13cb7338debbeb9375345230d51f8bcaeae82..017874ba4020e01a2d713a183ae2d40ed0c7e68b 100644 (file)
@@ -97,7 +97,10 @@ typedef zend_object_value (*zend_object_clone_obj_t)(zval *object TSRMLS_DC);
 typedef zend_class_entry *(*zend_object_get_class_entry_t)(zval *object TSRMLS_DC);
 typedef int (*zend_object_get_class_name_t)(zval *object, char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC);
 typedef int (*zend_object_compare_t)(zval *object1, zval *object2 TSRMLS_DC);
-typedef int (*zend_object_cast_t)(zval *readobj, zval *writeobj, int type, int should_free TSRMLS_DC);
+
+/* Cast an object to some other type
+ */
+typedef int (*zend_object_cast_t)(zval *readobj, zval *retval, int type TSRMLS_DC);
 
 /* updates *count to hold the number of elements present and returns SUCCESS.
  * Returns FAILURE if the object does not have any sense of overloaded dimensions */
@@ -138,7 +141,7 @@ ZEND_API zval **zend_std_get_static_property(zend_class_entry *ce, zend_uchar ty
 ZEND_API zend_bool zend_std_unset_static_property(zend_class_entry *ce, zend_uchar type, void *property_name, int property_name_len TSRMLS_DC);
 ZEND_API struct _zend_property_info *zend_get_property_info(zend_class_entry *ce, zval *member, int silent TSRMLS_DC);
 
-ZEND_API int zend_std_cast_object_tostring(zval *readobj, zval *writeobj, int type, int should_free TSRMLS_DC);
+ZEND_API int zend_std_cast_object_tostring(zval *readobj, zval *writeobj, int type TSRMLS_DC);
 
 
 #define IS_ZEND_STD_OBJECT(z)  ((z).type == IS_OBJECT && (Z_OBJ_HT((z))->get_class_entry != NULL))
index fda1e3ccaa9f99056f940d1d1b26f164c009c2e8..78f7c0d9717e22016278dd1b84a2f3fa3f71bdfb 100644 (file)
@@ -317,11 +317,17 @@ ZEND_API void convert_scalar_to_number(zval *op TSRMLS_DC)
        }
 
 
-#define convert_object_to_type(op, ctype, conv_func)                                                                                   \
+#define convert_object_to_type(op, ctype, conv_func)                                                                           \
        if (Z_OBJ_HT_P(op)->cast_object) {                                                                                                              \
-               if (Z_OBJ_HT_P(op)->cast_object(op, op, ctype, 1 TSRMLS_CC) == SUCCESS) {                       \
-                       op->type = ctype;                                                                                                                               \
+               zval *org;                                                                                                                                                      \
+               ALLOC_ZVAL(org);                                                                                                                                        \
+               *org = *op;                                                                                                                                                     \
+               if (Z_OBJ_HT_P(op)->cast_object(org, op, ctype TSRMLS_CC) == FAILURE) {                         \
+                       zend_error(E_RECOVERABLE_ERROR,                                                                                                 \
+                       "Object of class %v could not be converted to " # ctype, Z_OBJCE_P(org)->name); \
+                       INIT_ZVAL(*op);                                                                                                                                 \
                }                                                                                                                                                                       \
+               zval_dtor(org);                                                                                                                                         \
        } else {                                                                                                                                                                \
                if(Z_OBJ_HT_P(op)->get) {                                                                                                                       \
                        zval *newop = Z_OBJ_HT_P(op)->get(op TSRMLS_CC);                                                                \
@@ -496,10 +502,16 @@ ZEND_API void convert_to_null(zval *op)
 {
        if (op->type == IS_OBJECT) {
                if (Z_OBJ_HT_P(op)->cast_object) {
+                       zval *org;
                        TSRMLS_FETCH();
-                       if (Z_OBJ_HT_P(op)->cast_object(op, op, IS_NULL, 1 TSRMLS_CC) == SUCCESS) {
+
+                       ALLOC_ZVAL(org);
+                       *org = *op;
+                       if (Z_OBJ_HT_P(op)->cast_object(org, op, IS_NULL TSRMLS_CC) == SUCCESS) {
+                               zval_dtor(org);
                                return;
                        }
+                       *op = *org;
                }
        }