Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:1972 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 15774 invoked from network); 25 May 2003 00:15:10 -0000 Received: from unknown (HELO carmine.bestweb.net) (209.94.102.73) by pb1.pair.com with SMTP; 25 May 2003 00:15:10 -0000 Received: from [192.168.1.101] (ip216-179-71-153.cust.bestweb.net [216.179.71.153]) by carmine.bestweb.net (Postfix) with ESMTP id 85B9C23582; Sat, 24 May 2003 19:15:05 -0500 (EST) To: internals@lists.php.net Cc: Zeev Suraski , andi@zend.com, stas@zend.com Content-Type: multipart/mixed; boundary="=-/koCYyK2za5GdIQ4UhM1" Organization: Message-ID: <1053816554.355.13.camel@hasele> Mime-Version: 1.0 X-Mailer: Ximian Evolution 1.2.4 Date: 24 May 2003 18:49:15 -0400 Subject: cast_object() handler From: sterling@bumblebury.com (Sterling Hughes) --=-/koCYyK2za5GdIQ4UhM1 Content-Type: text/plain Content-Transfer-Encoding: 7bit Hi, Attached is a patch which allows one to intercept calls to object casting within the engine. This means that whenever an object is converted to a base type (except array, which has different semantics), a special object handler is called instead of the default conversion function. I've come across a need for this when implementing the simplexml extension, where i want an object to masquerade as either a string or a node. Take the following: slide.xml Why SimpleXML is cool With this new callback, the following syntax is perfectly valid: list; echo $list->bullet; // "Why SimpleXML is cool" echo $list->bullet->effect; // "slide" ?> Attached is a patch that makes this so. It only affects objects, and it is only a internal syntax (not exported to userspace). Every other place in the code that doesn't exploit this callback (sets it to NULL) will continue to operate as normal. -Sterling -- "Nothing is particularly hard if you divide it into small jobs." - Henry Ford --=-/koCYyK2za5GdIQ4UhM1 Content-Disposition: attachment; filename=cast_object.diff Content-Type: text/x-patch; name=cast_object.diff; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Index: zend.c =================================================================== RCS file: /repository/ZendEngine2/zend.c,v retrieving revision 1.227 diff -u -r1.227 zend.c --- zend.c 4 May 2003 18:21:32 -0000 1.227 +++ zend.c 25 May 2003 00:05:55 -0000 @@ -208,8 +208,12 @@ expr_copy->value.str.val = estrndup("Array", expr_copy->value.str.len); break; case IS_OBJECT: - 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); + if (expr->value.obj.handlers->cast_object) { + expr->value.obj.handlers->cast_object(expr, expr_copy, IS_STRING, 0 TSRMLS_CC); + } else { + 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); + } #if 0 /* FIXME: This might break BC for some people */ expr_copy->value.str.len = sizeof("Object")-1; Index: zend_object_handlers.c =================================================================== RCS file: /repository/ZendEngine2/zend_object_handlers.c,v retrieving revision 1.48 diff -u -r1.48 zend_object_handlers.c --- zend_object_handlers.c 21 May 2003 22:57:51 -0000 1.48 +++ zend_object_handlers.c 25 May 2003 00:05:57 -0000 @@ -830,7 +830,8 @@ zend_std_get_constructor, /* get_constructor */ 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_compare_objects, /* compare_objects */ + NULL, /* cast_object */ }; /* Index: zend_object_handlers.h =================================================================== RCS file: /repository/ZendEngine2/zend_object_handlers.h,v retrieving revision 1.14 diff -u -r1.14 zend_object_handlers.h --- zend_object_handlers.h 17 Feb 2003 14:06:39 -0000 1.14 +++ zend_object_handlers.h 25 May 2003 00:05:57 -0000 @@ -67,6 +67,8 @@ 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 void (*zend_object_cast_t)(zval *readobj, zval *writeobj, int type, int should_free TSRMLS_DC); + typedef struct _zend_object_handlers { /* general object functions */ @@ -90,6 +92,7 @@ zend_object_get_class_entry_t get_class_entry; zend_object_get_class_name_t get_class_name; zend_object_compare_t compare_objects; + zend_object_cast_t cast_object; } zend_object_handlers; extern zend_object_handlers std_object_handlers; Index: zend_operators.c =================================================================== RCS file: /repository/ZendEngine2/zend_operators.c,v retrieving revision 1.153 diff -u -r1.153 zend_operators.c --- zend_operators.c 23 May 2003 15:11:15 -0000 1.153 +++ zend_operators.c 25 May 2003 00:06:00 -0000 @@ -328,8 +328,12 @@ op->value.lval = tmp; break; case IS_OBJECT: - zval_dtor(op); - op->value.lval = 1; /* TBI!! */ + if (op->value.obj.handlers->cast_object) { + op->value.obj.handlers->cast_object(op, op, IS_LONG, 1 TSRMLS_CC); + } else { + zval_dtor(op); + op->value.lval = 1; + } break; default: zend_error(E_WARNING, "Cannot convert to ordinal value"); @@ -375,8 +379,12 @@ op->value.dval = tmp; break; case IS_OBJECT: - zval_dtor(op); - op->value.dval = 1; /* TBI!! */ + if (op->value.obj.handlers->cast_object) { + op->value.obj.handlers->cast_object(op, op, IS_DOUBLE, 1 TSRMLS_CC); + } else { + zval_dtor(op); + op->value.dval = 1; /* TBI!! */ + } break; default: zend_error(E_WARNING, "Cannot convert to real value (type=%d)", op->type); @@ -390,6 +398,13 @@ ZEND_API void convert_to_null(zval *op) { + if (op->type == IS_OBJECT) { + if (op->value.obj.handlers->cast_object) { + op->value.obj.handlers->cast_object(op, op, IS_NULL, 1 TSRMLS_CC); + return; + } + } + zval_dtor(op); op->type = IS_NULL; } @@ -435,8 +450,12 @@ op->value.lval = tmp; break; case IS_OBJECT: - zval_dtor(op); - op->value.lval = 1; /* TBI!! */ + if (op->value.obj.handlers->cast_object) { + op->value.obj.handlers->cast_object(op, op, IS_BOOL, 1 TSRMLS_CC); + } else { + zval_dtor(op); + op->value.lval = 1; /* TBI!! */ + } break; default: zval_dtor(op); @@ -497,10 +516,14 @@ zend_error(E_NOTICE, "Array to string conversion"); break; case IS_OBJECT: - zval_dtor(op); - op->value.str.val = estrndup_rel("Object", sizeof("Object")-1); - op->value.str.len = sizeof("Object")-1; - zend_error(E_NOTICE, "Object to string conversion"); + if (op->value.obj.handlers->cast_object) { + op->value.obj.handlers->cast_object(op, op, IS_STRING, 1 TSRMLS_CC); + } else { + zval_dtor(op); + op->value.str.val = estrndup_rel("Object", sizeof("Object")-1); + op->value.str.len = sizeof("Object")-1; + zend_error(E_NOTICE, "Object to string conversion"); + } break; default: zval_dtor(op); --=-/koCYyK2za5GdIQ4UhM1--