Skip to content

Instantly share code, notes, and snippets.

@ircmaxell
Created February 28, 2012 04:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ircmaxell/1929587 to your computer and use it in GitHub Desktop.
Save ircmaxell/1929587 to your computer and use it in GitHub Desktop.
POC for __castTo and __assign, NOTE: UNSTABLE
Index: Zend/zend.h
===================================================================
--- Zend/zend.h (revision 322430)
+++ Zend/zend.h (working copy)
@@ -486,6 +486,8 @@
union _zend_function *__call;
union _zend_function *__callstatic;
union _zend_function *__tostring;
+ union _zend_function *__castto;
+ union _zend_function *__assign;
union _zend_function *serialize_func;
union _zend_function *unserialize_func;
Index: Zend/zend_object_handlers.c
===================================================================
--- Zend/zend_object_handlers.c (revision 322430)
+++ Zend/zend_object_handlers.c (working copy)
@@ -1482,6 +1482,89 @@
}
/* }}} */
+ZEND_API int zend_std_cast_object(zval *readobj, zval *writeobj, int type TSRMLS_DC) /* {{{ */
+{
+ zend_class_entry *ce = Z_OBJCE_P(readobj);
+ if (ce->__castto) {
+ zval *typearg, *retval;
+ ALLOC_INIT_ZVAL(retval);
+ ALLOC_INIT_ZVAL(typearg);
+ switch (type) {
+ case IS_NULL:
+ ZVAL_STRING(typearg, "NULL", 1);
+ break;
+ case IS_BOOL:
+ ZVAL_STRING(typearg, "boolean", 1);
+ break;
+ case IS_LONG:
+ ZVAL_STRING(typearg, "integer", 1);
+ break;
+ case IS_DOUBLE:
+ ZVAL_STRING(typearg, "double", 1);
+ break;
+ case IS_STRING:
+ ZVAL_STRING(typearg, "string", 1);
+ break;
+ case IS_ARRAY:
+ ZVAL_STRING(typearg, "array", 1);
+ break;
+ case IS_OBJECT:
+ ZVAL_STRING(typearg, "object", 1);
+ break;
+ case IS_RESOURCE:
+ ZVAL_STRING(typearg, "resource", 1);
+ break;
+ case IS_CALLABLE:
+ ZVAL_STRING(typearg, "callable", 1);
+ break;
+ default:
+ ZVAL_STRING(typearg, "native", 1);
+ break;
+ }
+ if (zend_call_method_with_1_params(&readobj, ce, &ce->__castto, "__castto", &retval, typearg)) {
+ ZVAL_ZVAL(writeobj, retval, 1, 1);
+ zval_dtor(retval);
+ zval_dtor(typearg);
+ return SUCCESS;
+ }
+ zval_dtor(retval);
+ zval_dtor(typearg);
+
+
+ }
+ 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;
+ ALLOC_INIT_ZVAL(retval);
+ if (FAILURE != zend_std_cast_object(readobj, retval, -1 TSRMLS_CC)) {
+ return retval;
+ }
+ ZVAL_NULL(retval);
+ return retval;
+}
+/* }}} */
+
+ZEND_API void zend_std_cast_object_set(zval **obj, zval *value TSRMLS_DC) /* {{{ */
+{
+ zval *retval;
+ zend_class_entry *ce = Z_OBJCE_PP(obj);
+ if (ce->__assign &&
+ (zend_call_method_with_1_params(obj, ce, &ce->__assign, "__assign", &retval, value)) && retval) {
+ if (Z_TYPE_P(retval) != IS_BOOL || Z_BVAL_P(retval)) {
+ zval_dtor(retval);
+ return;
+ }
+ zval_dtor(retval);
+ }
+ ZVAL_ZVAL(*obj, value, 1, 1);
+
+}
+/* }}} */
+
ZEND_API int zend_std_cast_object_tostring(zval *readobj, zval *writeobj, int type TSRMLS_DC) /* {{{ */
{
zval *retval;
@@ -1588,25 +1671,25 @@
zend_std_write_property, /* write_property */
zend_std_read_dimension, /* read_dimension */
zend_std_write_dimension, /* write_dimension */
- zend_std_get_property_ptr_ptr, /* get_property_ptr_ptr */
- NULL, /* get */
- NULL, /* set */
+ zend_std_get_property_ptr_ptr, /* get_property_ptr_ptr */
+ zend_std_cast_object_get, /* get */
+ zend_std_cast_object_set, /* set */
zend_std_has_property, /* has_property */
zend_std_unset_property, /* unset_property */
zend_std_has_dimension, /* has_dimension */
zend_std_unset_dimension, /* unset_dimension */
zend_std_get_properties, /* get_properties */
zend_std_get_method, /* get_method */
- NULL, /* call_method */
+ NULL, /* call_method */
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_object_get_class_name, /* get_class_name */
zend_std_compare_objects, /* compare_objects */
- zend_std_cast_object_tostring, /* cast_object */
- NULL, /* count_elements */
- NULL, /* get_debug_info */
+ zend_std_cast_object, /* cast_object */
+ NULL, /* count_elements */
+ NULL, /* get_debug_info */
zend_std_get_closure, /* get_closure */
- zend_std_get_gc, /* get_gc */
+ zend_std_get_gc, /* get_gc */
};
/*
Index: Zend/zend_compile.c
===================================================================
--- Zend/zend_compile.c (revision 322430)
+++ Zend/zend_compile.c (working copy)
@@ -1617,7 +1617,16 @@
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_CASTTO_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CASTTO_FUNC_NAME, sizeof(ZEND_CASTTO_FUNC_NAME)-1))) {
+ if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
+ zend_error(E_WARNING, "The magic method __castto() must have public visibility and cannot be static");
+ }
+ } else if ((name_len == sizeof(ZEND_ASSIGN_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_ASSIGN_FUNC_NAME, sizeof(ZEND_ASSIGN_FUNC_NAME)-1))) {
+ if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
+ zend_error(E_WARNING, "The magic method __assign() must have public visibility and cannot be static");
+ }
}
+
} else {
char *class_lcname;
@@ -1668,6 +1677,16 @@
zend_error(E_WARNING, "The magic method __isset() must have public visibility and cannot be static");
}
CG(active_class_entry)->__isset = (zend_function *) CG(active_op_array);
+ } else if ((name_len == sizeof(ZEND_CASTTO_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CASTTO_FUNC_NAME, sizeof(ZEND_CASTTO_FUNC_NAME)-1))) {
+ if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
+ zend_error(E_WARNING, "The magic method __castto() must have public visibility and cannot be static");
+ }
+ CG(active_class_entry)->__castto = (zend_function *) CG(active_op_array);
+ } else if ((name_len == sizeof(ZEND_ASSIGN_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_ASSIGN_FUNC_NAME, sizeof(ZEND_ASSIGN_FUNC_NAME)-1))) {
+ if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
+ zend_error(E_WARNING, "The magic method __assign() must have public visibility and cannot be static");
+ }
+ CG(active_class_entry)->__assign = (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)-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");
@@ -2836,6 +2855,12 @@
if (!ce->__callstatic) {
ce->__callstatic = ce->parent->__callstatic;
}
+ if (!ce->__castto) {
+ ce->__castto = ce->parent->__castto;
+ }
+ if (!ce->__assign) {
+ ce->__assign = ce->parent->__assign;
+ }
if (!ce->__tostring) {
ce->__tostring = ce->parent->__tostring;
}
@@ -3730,6 +3755,10 @@
ce->__unset = fe;
} else if (!strncmp(mname, ZEND_ISSET_FUNC_NAME, mname_len)) {
ce->__isset = fe;
+ } else if (!strncmp(mname, ZEND_CASTTO_FUNC_NAME, mname_len)) {
+ ce->__castto = fe;
+ } else if (!strncmp(mname, ZEND_ASSIGN_FUNC_NAME, mname_len)) {
+ ce->__assign = fe;
} else if (!strncmp(mname, ZEND_CALLSTATIC_FUNC_NAME, mname_len)) {
ce->__callstatic = fe;
} else if (!strncmp(mname, ZEND_TOSTRING_FUNC_NAME, mname_len)) {
@@ -6750,6 +6779,8 @@
ce->__isset = NULL;
ce->__call = NULL;
ce->__callstatic = NULL;
+ ce->__castto = NULL;
+ ce->__assign = NULL;
ce->__tostring = NULL;
ce->create_object = NULL;
ce->get_iterator = NULL;
Index: Zend/zend_object_handlers.h
===================================================================
--- Zend/zend_object_handlers.h (revision 322430)
+++ Zend/zend_object_handlers.h (working copy)
@@ -155,6 +155,9 @@
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_cast_object(zval *readobj, zval *writeobj, int type TSRMLS_DC);
+ZEND_API zval *zend_std_cast_object_get(zval *readobj TSRMLS_DC);
+ZEND_API void zend_std_cast_object_set(zval **obj, zval *value 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 322430)
+++ Zend/zend_compile.h (working copy)
@@ -830,6 +830,8 @@
#define ZEND_CALLSTATIC_FUNC_NAME "__callstatic"
#define ZEND_TOSTRING_FUNC_NAME "__tostring"
#define ZEND_AUTOLOAD_FUNC_NAME "__autoload"
+#define ZEND_CASTTO_FUNC_NAME "__castto"
+#define ZEND_ASSIGN_FUNC_NAME "__assign"
/* The following constants may be combined in CG(compiler_options)
* to change the default compiler behavior */
Index: Zend/zend_API.c
===================================================================
--- Zend/zend_API.c (revision 322430)
+++ Zend/zend_API.c (working copy)
@@ -1926,7 +1926,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, *__castto = NULL, *__assign = NULL;
const char *lowercase_name;
int fname_len;
const char *lc_class_name = NULL;
@@ -2069,6 +2069,10 @@
__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_CASTTO_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_CASTTO_FUNC_NAME, sizeof(ZEND_CASTTO_FUNC_NAME))) {
+ __castto = reg_function;
+ } else if ((fname_len == sizeof(ZEND_ASSIGN_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_ASSIGN_FUNC_NAME, sizeof(ZEND_ASSIGN_FUNC_NAME))) {
+ __assign = reg_function;
} else {
reg_function = NULL;
}
@@ -2107,6 +2111,8 @@
scope->__set = __set;
scope->__unset = __unset;
scope->__isset = __isset;
+ scope->__castto = __castto;
+ scope->__assign = __assign;
if (ctor) {
ctor->common.fn_flags |= ZEND_ACC_CTOR;
if (ctor->common.fn_flags & ZEND_ACC_STATIC) {
@@ -2170,6 +2176,18 @@
}
__isset->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
}
+ if (__castto) {
+ if (__castto->common.fn_flags & ZEND_ACC_STATIC) {
+ zend_error(error_type, "Method %s::%s() cannot be static", scope->name, __castto->common.function_name);
+ }
+ __castto->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
+ }
+ if (__assign) {
+ if (__assign->common.fn_flags & ZEND_ACC_STATIC) {
+ zend_error(error_type, "Method %s::%s() cannot be static", scope->name, __assign->common.function_name);
+ }
+ __assign->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
+ }
efree((char*)lc_class_name);
}
return SUCCESS;
Index: Zend/zend_API.h
===================================================================
--- Zend/zend_API.h (revision 322430)
+++ Zend/zend_API.h (working copy)
@@ -190,6 +190,8 @@
class_container.__set = handle_propset; \
class_container.__unset = handle_propunset; \
class_container.__isset = handle_propisset; \
+ class_container.__castto = NULL; \
+ class_container.__assign = NULL; \
class_container.serialize_func = NULL; \
class_container.unserialize_func = NULL; \
class_container.serialize = NULL; \
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment