php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Return to Bug #45002
Patch Fix revision 2011-05-19 10:01 UTC by allesbesser at gmail dot com

Patch Fix for Scripting Engine problem Bug #45002

Patch version 2011-05-19 10:01 UTC

Return to Bug #45002 | Download this patch
Patch Revisions:

Developer: allesbesser@gmail.com

Index: zend.h
===================================================================
RCS file: /repository/ZendEngine2/zend.h,v
retrieving revision 1.293.2.11.2.9.2.28
diff -u -r1.293.2.11.2.9.2.28 zend.h
--- zend.h	15 Aug 2008 19:47:23 -0000	1.293.2.11.2.9.2.28
+++ zend.h	8 Sep 2008 09:06:13 -0000
@@ -432,8 +432,12 @@
 	union _zend_function *clone;
 	union _zend_function *__get;
 	union _zend_function *__set;
+	union _zend_function *__getstatic;
+	union _zend_function *__setstatic;
 	union _zend_function *__unset;
 	union _zend_function *__isset;
+	union _zend_function *__unsetstatic;
+	union _zend_function *__issetstatic;
 	union _zend_function *__call;
 	union _zend_function *__callstatic;
 	union _zend_function *__tostring;
@@ -462,6 +466,7 @@
 	zend_uint doc_comment_len;
 
 	struct _zend_module_entry *module;
+	HashTable *guards;
 };
 
 #include "zend_stream.h"
Index: zend_API.c
===================================================================
RCS file: /repository/ZendEngine2/zend_API.c,v
retrieving revision 1.296.2.27.2.34.2.53
diff -u -r1.296.2.27.2.34.2.53 zend_API.c
--- zend_API.c	22 Aug 2008 14:51:30 -0000	1.296.2.27.2.34.2.53
+++ zend_API.c	8 Sep 2008 09:06:15 -0000
@@ -1774,7 +1774,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, *__callstatic = NULL, *__tostring = NULL;
+	zend_function *ctor = NULL, *dtor = NULL, *clone = NULL, *__get = NULL, *__set = NULL, *__getstatic = NULL, *__setstatic = NULL, *__unset = NULL, *__isset = NULL, *__unsetstatic = NULL, *__issetstatic = NULL, *__call = NULL, *__callstatic = NULL, *__tostring = NULL;
 	char *lowercase_name;
 	int fname_len;
 	char *lc_class_name = NULL;
@@ -1900,10 +1900,18 @@
 				__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))) {
 				__set = reg_function;
+			} else if ((fname_len == sizeof(ZEND_GETSTATIC_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_GETSTATIC_FUNC_NAME, sizeof(ZEND_GETSTATIC_FUNC_NAME))) {
+				__getstatic = reg_function;
+			} else if ((fname_len == sizeof(ZEND_SETSTATIC_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_SETSTATIC_FUNC_NAME, sizeof(ZEND_SETSTATIC_FUNC_NAME))) {
+				__setstatic = reg_function;
 			} else if ((fname_len == sizeof(ZEND_UNSET_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_UNSET_FUNC_NAME, sizeof(ZEND_UNSET_FUNC_NAME))) {
 				__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_UNSETSTATIC_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_UNSETSTATIC_FUNC_NAME, sizeof(ZEND_UNSETSTATIC_FUNC_NAME))) {
+				__unsetstatic = reg_function;
+			} else if ((fname_len == sizeof(ZEND_ISSETSTATIC_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_ISSETSTATIC_FUNC_NAME, sizeof(ZEND_ISSETSTATIC_FUNC_NAME))) {
+				__issetstatic = reg_function;
 			} else {
 				reg_function = NULL;
 			}
@@ -1941,8 +1949,12 @@
 		scope->__tostring = __tostring;
 		scope->__get = __get;
 		scope->__set = __set;
+		scope->__getstatic = __getstatic;
+		scope->__setstatic = __setstatic;
 		scope->__unset = __unset;
 		scope->__isset = __isset;
+		scope->__unsetstatic = __unsetstatic;
+		scope->__issetstatic = __issetstatic;
 		if (ctor) {
 			ctor->common.fn_flags |= ZEND_ACC_CTOR;
 			if (ctor->common.fn_flags & ZEND_ACC_STATIC) {
@@ -1994,6 +2006,18 @@
 			}
 			__set->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
 		}
+		if (__getstatic) {
+			if (!(__getstatic->common.fn_flags & ZEND_ACC_STATIC)) {
+				zend_error(error_type, "Method %s::%s() must be static", scope->name, __getstatic->common.function_name);
+			}
+			__getstatic->common.fn_flags |= ~ZEND_ACC_ALLOW_STATIC;
+		}
+		if (__setstatic) {
+			if (!(__setstatic->common.fn_flags & ZEND_ACC_STATIC)) {
+				zend_error(error_type, "Method %s::%s() must be static", scope->name, __setstatic->common.function_name);
+			}
+			__setstatic->common.fn_flags |= ~ZEND_ACC_ALLOW_STATIC;
+		}
 		if (__unset) {
 			if (__unset->common.fn_flags & ZEND_ACC_STATIC) {
 				zend_error(error_type, "Method %s::%s() cannot be static", scope->name, __unset->common.function_name);
@@ -2006,6 +2030,18 @@
 			}
 			__isset->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
 		}
+		if (__unsetstatic) {
+			if (!(__unsetstatic->common.fn_flags & ZEND_ACC_STATIC)) {
+				zend_error(error_type, "Method %s::%s() must be static", scope->name, __unsetstatic->common.function_name);
+			}
+			__unsetstatic->common.fn_flags |= ~ZEND_ACC_ALLOW_STATIC;
+		}
+		if (__issetstatic) {
+			if (!(__issetstatic->common.fn_flags & ZEND_ACC_STATIC)) {
+				zend_error(error_type, "Method %s::%s() must be static", scope->name, __issetstatic->common.function_name);
+			}
+			__issetstatic->common.fn_flags |= ~ZEND_ACC_ALLOW_STATIC;
+		}
 		efree(lc_class_name);
 	}
 	return SUCCESS;
Index: zend_compile.c
===================================================================
RCS file: /repository/ZendEngine2/zend_compile.c,v
retrieving revision 1.647.2.27.2.41.2.85
diff -u -r1.647.2.27.2.41.2.85 zend_compile.c
--- zend_compile.c	29 Aug 2008 10:17:08 -0000	1.647.2.27.2.41.2.85
+++ zend_compile.c	8 Sep 2008 09:06:17 -0000
@@ -636,6 +636,21 @@
 					return;
 				} else if (opline_is_fetch_this(last_op TSRMLS_CC)) {
 					zend_error(E_COMPILE_ERROR, "Cannot re-assign $this");
+				} else if (last_op->opcode == ZEND_FETCH_W && last_op->op2.u.EA.type == ZEND_FETCH_STATIC_MEMBER) {
+					if (n > 0) {
+						*opline = *last_op;
+						MAKE_NOP(last_op);
+						last_op = opline;
+						opline = get_next_op(CG(active_op_array) TSRMLS_CC);
+					}
+					last_op->opcode = ZEND_ASSIGN_CLASS;
+					zend_do_op_data(opline, value TSRMLS_CC);
+					opline->op2.u.var = get_temporary_variable(CG(active_op_array));
+					opline->op2.u.EA.type = 0;
+					opline->op2.op_type = IS_VAR;
+					SET_UNUSED(opline->result);
+					*result = last_op->result;
+					return;
 				} else {
 					break;
 				}
@@ -1288,6 +1303,16 @@
 					zend_error(E_WARNING, "The magic method __set() must have public visibility and can not be static");
 				}
 				CG(active_class_entry)->__set = (zend_function *) CG(active_op_array);
+			} else if ((name_len == sizeof(ZEND_GETSTATIC_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_GETSTATIC_FUNC_NAME, sizeof(ZEND_GETSTATIC_FUNC_NAME)-1))) {
+				if ((fn_flags & (ZEND_ACC_PPP_MASK ^ ZEND_ACC_PUBLIC)) || (fn_flags & ZEND_ACC_STATIC) == 0) {
+					zend_error(E_WARNING, "The magic method __getStatic() must have public visibility and be static");
+				}
+				CG(active_class_entry)->__getstatic = (zend_function *) CG(active_op_array);
+			} else if ((name_len == sizeof(ZEND_SETSTATIC_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_SETSTATIC_FUNC_NAME, sizeof(ZEND_SETSTATIC_FUNC_NAME)-1))) {
+				if ((fn_flags & (ZEND_ACC_PPP_MASK ^ ZEND_ACC_PUBLIC)) || (fn_flags & ZEND_ACC_STATIC) == 0) {
+					zend_error(E_WARNING, "The magic method __setStatic() must have public visibility and be static");
+				}
+				CG(active_class_entry)->__setstatic = (zend_function *) CG(active_op_array);
 			} else if ((name_len == sizeof(ZEND_UNSET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_UNSET_FUNC_NAME, sizeof(ZEND_UNSET_FUNC_NAME)-1))) {
 				if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
 					zend_error(E_WARNING, "The magic method __unset() must have public visibility and can not be static");
@@ -1298,6 +1323,16 @@
 					zend_error(E_WARNING, "The magic method __isset() must have public visibility and can not be static");
 				}
 				CG(active_class_entry)->__isset = (zend_function *) CG(active_op_array);
+			} else if ((name_len == sizeof(ZEND_ISSETSTATIC_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_ISSETSTATIC_FUNC_NAME, sizeof(ZEND_ISSETSTATIC_FUNC_NAME)-1))) {
+				if ((fn_flags & (ZEND_ACC_PPP_MASK ^ ZEND_ACC_PUBLIC)) || (fn_flags & ZEND_ACC_STATIC) == 0) {
+					zend_error(E_WARNING, "The magic method __issetStatic() must have public visibility and be static");
+				}
+				CG(active_class_entry)->__issetstatic = (zend_function *) CG(active_op_array);
+			} else if ((name_len == sizeof(ZEND_UNSETSTATIC_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_UNSETSTATIC_FUNC_NAME, sizeof(ZEND_UNSETSTATIC_FUNC_NAME)-1))) {
+				if ((fn_flags & (ZEND_ACC_PPP_MASK ^ ZEND_ACC_PUBLIC)) || (fn_flags & ZEND_ACC_STATIC) == 0) {
+					zend_error(E_WARNING, "The magic method __unsetStatic() must have public visibility and be static");
+				}
+				CG(active_class_entry)->__unsetstatic = (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 can not be static");
@@ -2394,12 +2429,24 @@
 	if (!ce->__set) {
 		ce->__set = ce->parent->__set;
 	}
+	if (!ce->__getstatic) {
+		ce->__getstatic   = ce->parent->__getstatic;
+	}
+	if (!ce->__setstatic) {
+		ce->__setstatic = ce->parent->__setstatic;
+	}
 	if (!ce->__unset) {
 		ce->__unset = ce->parent->__unset;
 	}
 	if (!ce->__isset) {
 		ce->__isset = ce->parent->__isset;
 	}
+	if (!ce->__unsetstatic) {
+		ce->__unsetstatic = ce->parent->__unsetstatic;
+	}
+	if (!ce->__issetstatic) {
+		ce->__issetstatic = ce->parent->__issetstatic;
+	}
 	if (!ce->__call) {
 		ce->__call = ce->parent->__call;
 	}
@@ -4929,6 +4976,8 @@
 
 	ce->doc_comment = NULL;
 	ce->doc_comment_len = 0;
+    
+	ce->guards = NULL;
 
 	zend_hash_init_ex(&ce->default_properties, 0, NULL, zval_ptr_dtor_func, persistent_hashes, 0);
 	zend_hash_init_ex(&ce->properties_info, 0, NULL, (dtor_func_t) (persistent_hashes ? zend_destroy_property_info_internal : zend_destroy_property_info), persistent_hashes, 0);
@@ -4960,8 +5009,12 @@
 		ce->clone = NULL;
 		ce->__get = NULL;
 		ce->__set = NULL;
+		ce->__getstatic = NULL;
+		ce->__setstatic = NULL;
 		ce->__unset = NULL;
 		ce->__isset = NULL;
+		ce->__unsetstatic = NULL;
+		ce->__issetstatic = NULL;
 		ce->__call = NULL;
 		ce->__callstatic = NULL;
 		ce->__tostring = NULL;
Index: zend_compile.h
===================================================================
RCS file: /repository/ZendEngine2/zend_compile.h,v
retrieving revision 1.316.2.8.2.12.2.33
diff -u -r1.316.2.8.2.12.2.33 zend_compile.h
--- zend_compile.h	29 Aug 2008 18:12:47 -0000	1.316.2.8.2.12.2.33
+++ zend_compile.h	8 Sep 2008 09:06:17 -0000
@@ -737,8 +737,12 @@
 #define ZEND_DESTRUCTOR_FUNC_NAME	"__destruct"
 #define ZEND_GET_FUNC_NAME          "__get"
 #define ZEND_SET_FUNC_NAME          "__set"
+#define ZEND_GETSTATIC_FUNC_NAME    "__getstatic"
+#define ZEND_SETSTATIC_FUNC_NAME    "__setstatic"
 #define ZEND_UNSET_FUNC_NAME        "__unset"
 #define ZEND_ISSET_FUNC_NAME        "__isset"
+#define ZEND_UNSETSTATIC_FUNC_NAME  "__unsetstatic"
+#define ZEND_ISSETSTATIC_FUNC_NAME  "__issetstatic"
 #define ZEND_CALL_FUNC_NAME         "__call"
 #define ZEND_CALLSTATIC_FUNC_NAME   "__callstatic"
 #define ZEND_TOSTRING_FUNC_NAME     "__tostring"
Index: zend_object_handlers.c
===================================================================
RCS file: /repository/ZendEngine2/zend_object_handlers.c,v
retrieving revision 1.135.2.6.2.22.2.20
diff -u -r1.135.2.6.2.22.2.20 zend_object_handlers.c
--- zend_object_handlers.c	14 Aug 2008 21:36:56 -0000	1.135.2.6.2.22.2.20
+++ zend_object_handlers.c	8 Sep 2008 09:06:19 -0000
@@ -308,6 +308,23 @@
 	stub.in_isset = 0;
 	return zend_hash_quick_add(zobj->guards, property_info->name, property_info->name_length+1, property_info->h, (void**)&stub, sizeof(stub), (void**) pguard);
 }
+
+static int zend_get_class_property_guard(zend_class_entry *ce, zend_property_info *property_info, zend_guard **pguard) /* {{{ */
+{
+	zend_guard stub;
+
+	if (!ce->guards) {
+		ALLOC_HASHTABLE(ce->guards);
+		zend_hash_init(ce->guards, 0, NULL, NULL, 0);
+	} else if (zend_hash_quick_find(ce->guards, property_info->name, property_info->name_length+1, property_info->h, (void **) pguard) == SUCCESS) {
+		return SUCCESS;
+	}
+	stub.in_get = 0;
+	stub.in_set = 0;
+	stub.in_unset = 0;
+	stub.in_isset = 0;
+	return zend_hash_quick_add(ce->guards, property_info->name, property_info->name_length+1, property_info->h, (void**)&stub, sizeof(stub), (void**) pguard);
+}
 /* }}} */
 
 zval *zend_std_read_property(zval *object, zval *member, int type TSRMLS_DC) /* {{{ */
@@ -978,6 +995,74 @@
 }
 /* }}} */
 
+ZEND_API int zend_std_set_static_property(zend_class_entry *ce, char *property_name, int property_name_len, zval** value TSRMLS_DC) /* {{{ */
+{
+	zval **retval = NULL;
+	zend_class_entry *tmp_ce = ce;
+	zend_property_info *property_info;
+	zend_property_info std_property_info;
+
+#if DEBUG_OBJECT_HANDLERS
+	fprintf(stderr, "%s::$%s = ", ce->name, property_name);
+    zend_print_zval_r(*value, 2 TSRMLS_CC);
+#endif
+	
+	if (zend_hash_find(&ce->properties_info, property_name, property_name_len+1, (void **) &property_info)==FAILURE) {
+		std_property_info.flags = ZEND_ACC_PUBLIC;
+		std_property_info.name = property_name;
+		std_property_info.name_length = property_name_len;
+		std_property_info.h = zend_get_hash_value(std_property_info.name, std_property_info.name_length+1);
+		std_property_info.ce = ce;
+		property_info = &std_property_info;
+	}
+
+	if (!zend_verify_property_access(property_info, ce TSRMLS_CC)) {
+		zend_error(E_ERROR, "Cannot access %s property %s::$%s", zend_visibility_string(property_info->flags), ce->name, property_name);
+		return 0;
+	}
+
+	zend_update_class_constants(tmp_ce TSRMLS_CC);
+	zend_hash_quick_find(CE_STATIC_MEMBERS(tmp_ce), property_info->name, property_info->name_length+1, property_info->h, (void **) &retval);
+
+	if (!retval) {
+		zend_property_info property_info;
+		zend_guard *guard;
+
+		if (!ce->__setstatic) {
+			zend_error(E_ERROR, "Cannot access undeclared property %s::$%s", ce->name, property_name);
+			return NULL;
+		}
+
+		property_info.flags = ZEND_ACC_PUBLIC;
+		property_info.name = property_name;
+		property_info.name_length = property_name_len;
+		property_info.h = zend_get_hash_value(property_info.name, property_info.name_length+1);
+		property_info.ce = ce;
+
+		if (zend_get_class_property_guard(ce, &property_info, &guard) == SUCCESS && !guard->in_set) {
+			zval *member;
+			zval *return_value = NULL;
+			zend_class_entry *scope;
+
+			ALLOC_INIT_ZVAL(member);
+			ZVAL_STRING(member, property_info.name, 0);
+
+			guard->in_set = 1; /* prevent circular getting */
+			scope = EG(called_scope);
+			EG(called_scope)= ce;
+			zend_call_method_with_2_params(NULL, ce, &ce->__setstatic, ZEND_SETSTATIC_FUNC_NAME, &return_value, member, *value);
+			EG(called_scope)= scope;
+			guard->in_set = 0;
+		}
+    
+    } else {
+        *retval = *value;
+        zval_copy_ctor(*retval);
+    }
+	
+    return 1;
+}
+
 ZEND_API zval **zend_std_get_static_property(zend_class_entry *ce, char *property_name, int property_name_len, zend_bool silent TSRMLS_DC) /* {{{ */
 {
 	zval **retval = NULL;
@@ -1010,6 +1095,43 @@
 	zend_hash_quick_find(CE_STATIC_MEMBERS(tmp_ce), property_info->name, property_info->name_length+1, property_info->h, (void **) &retval);
 
 	if (!retval) {
+		zend_guard *guard;
+		zend_function *interceptor = silent ? ce->__issetstatic : ce->__getstatic;
+
+		if (interceptor && zend_get_class_property_guard(ce, property_info, &guard) == SUCCESS) {
+			zend_bool *in_interceptor;
+			char *interceptor_name;
+
+			if (silent) {
+				in_interceptor = &guard->in_isset;
+				interceptor_name = ZEND_ISSETSTATIC_FUNC_NAME;
+			} else {
+				in_interceptor = &guard->in_get;
+				interceptor_name = ZEND_GETSTATIC_FUNC_NAME;
+			}
+
+			if (!*in_interceptor) {
+				zval *member;
+				zval *return_value = NULL;
+				zend_class_entry *scope;
+
+				ALLOC_INIT_ZVAL(member);
+				ZVAL_STRING(member, property_info->name, 0);
+
+				*in_interceptor = 1; /* prevent circular getting */
+				scope = EG(called_scope);
+				EG(called_scope)= ce;
+				zend_call_method_with_1_params(NULL, ce, &interceptor, interceptor_name, &return_value, member);
+				EG(called_scope)= scope;
+				*in_interceptor = 0;
+
+				if (return_value) {
+					retval = &return_value;
+					return retval;
+				}
+			}
+		}
+
 		if (silent) {
 			return NULL;
 		} else {
@@ -1023,8 +1145,44 @@
 
 ZEND_API zend_bool zend_std_unset_static_property(zend_class_entry *ce, char *property_name, int property_name_len TSRMLS_DC) /* {{{ */
 {
+
+	/* We will allow unsetting of static properties only if:
+	 * a) __unsetStatic() is defined
+	 * b) the member does not exist as declared member
+	 * Otherwise, we'll raise a E_ERROR
+	 */
+	if (ce->__unsetstatic && !zend_hash_exists(&ce->properties_info, property_name, property_name_len+1)) {
+		zend_property_info property_info;
+		zend_guard *guard;
+
+		property_info.flags = ZEND_ACC_PUBLIC;
+		property_info.name = property_name;
+		property_info.name_length = property_name_len;
+		property_info.h = zend_get_hash_value(property_info.name, property_info.name_length+1);
+		property_info.ce = ce;
+
+		if (zend_get_class_property_guard(ce, &property_info, &guard) == SUCCESS && !guard->in_unset) {
+			zval *member;
+			zval *return_value = NULL;
+			zend_class_entry *scope;
+
+			ALLOC_INIT_ZVAL(member);
+			ZVAL_STRING(member, property_info.name, 0);
+
+			guard->in_unset = 1; /* prevent circular getting */
+			scope = EG(called_scope);
+			EG(called_scope)= ce;
+			zend_call_method_with_1_params(NULL, ce, &ce->__unsetstatic, ZEND_UNSETSTATIC_FUNC_NAME, &return_value, member);
+			EG(called_scope)= scope;
+			guard->in_unset = 0;
+
+			if (return_value) {
+				return 1;
+			}
+		}
+	}
 	zend_error(E_ERROR, "Attempt to unset static property %s::$%s", ce->name, property_name);
-	return 0;
+	return 0;	
 }
 /* }}} */
 
Index: zend_object_handlers.h
===================================================================
RCS file: /repository/ZendEngine2/zend_object_handlers.h,v
retrieving revision 1.47.2.2.2.5.2.5
diff -u -r1.47.2.2.2.5.2.5 zend_object_handlers.h
--- zend_object_handlers.h	14 Aug 2008 21:36:56 -0000	1.47.2.2.2.5.2.5
+++ zend_object_handlers.h	8 Sep 2008 09:06:20 -0000
@@ -145,6 +145,7 @@
 BEGIN_EXTERN_C()
 ZEND_API union _zend_function *zend_std_get_static_method(zend_class_entry *ce, char *function_name_strval, int function_name_strlen TSRMLS_DC);
 ZEND_API zval **zend_std_get_static_property(zend_class_entry *ce, char *property_name, int property_name_len, zend_bool silent TSRMLS_DC);
+ZEND_API int zend_std_set_static_property(zend_class_entry *ce, char *property_name, int property_name_len, zval **value TSRMLS_DC);
 ZEND_API zend_bool zend_std_unset_static_property(zend_class_entry *ce, char *property_name, int property_name_len TSRMLS_DC);
 ZEND_API union _zend_function *zend_std_get_constructor(zval *object TSRMLS_DC);
 ZEND_API struct _zend_property_info *zend_get_property_info(zend_class_entry *ce, zval *member, int silent TSRMLS_DC);
Index: zend_opcode.c
===================================================================
RCS file: /repository/ZendEngine2/zend_opcode.c,v
retrieving revision 1.110.2.6.2.3.2.9
diff -u -r1.110.2.6.2.3.2.9 zend_opcode.c
--- zend_opcode.c	29 Aug 2008 18:12:47 -0000	1.110.2.6.2.3.2.9
+++ zend_opcode.c	8 Sep 2008 09:06:20 -0000
@@ -179,6 +179,10 @@
 	if (--ce->refcount > 0) {
 		return;
 	}
+	if (ce->guards) {
+		zend_hash_destroy(ce->guards);
+		FREE_HASHTABLE(ce->guards);		
+	}
 	switch (ce->type) {
 		case ZEND_USER_CLASS:
 			zend_hash_destroy(&ce->default_properties);
Index: zend_vm_def.h
===================================================================
RCS file: /repository/ZendEngine2/zend_vm_def.h,v
retrieving revision 1.59.2.29.2.48.2.70
diff -u -r1.59.2.29.2.48.2.70 zend_vm_def.h
--- zend_vm_def.h	15 Aug 2008 19:47:28 -0000	1.59.2.29.2.48.2.70
+++ zend_vm_def.h	8 Sep 2008 09:06:22 -0000
@@ -1503,6 +1503,22 @@
 	ZEND_VM_NEXT_OPCODE();
 }
 
+ZEND_VM_HANDLER(137, ZEND_ASSIGN_CLASS, CONST, CONST|TMP|VAR|CV)
+{
+	zend_op *opline = EX(opline);
+	zend_op *op_data = opline+1;
+	zend_free_op free_op1;
+	zend_free_op free_value;
+	zval *varname = GET_OP1_ZVAL_PTR(BP_VAR_R);
+	zval *value = get_zval_ptr(&op_data->op1, EX(Ts), &free_value, BP_VAR_R);
+
+	zend_std_set_static_property(EX_T(opline->op2.u.var).class_entry, Z_STRVAL_P(varname), Z_STRLEN_P(varname), &value TSRMLS_CC);
+
+	/* assign_class has two opcodes! */
+	ZEND_VM_INC_OPCODE();
+	ZEND_VM_NEXT_OPCODE();
+}
+
 ZEND_VM_HANDLER(147, ZEND_ASSIGN_DIM, VAR|CV, CONST|TMP|VAR|UNUSED|CV)
 {
 	zend_op *opline = EX(opline);
Index: zend_vm_execute.h
===================================================================
RCS file: /repository/ZendEngine2/zend_vm_execute.h,v
retrieving revision 1.62.2.30.2.49.2.70
diff -u -r1.62.2.30.2.49.2.70 zend_vm_execute.h
--- zend_vm_execute.h	15 Aug 2008 19:47:28 -0000	1.62.2.30.2.49.2.70
+++ zend_vm_execute.h	8 Sep 2008 09:06:36 -0000
@@ -2595,6 +2595,22 @@
 	ZEND_VM_NEXT_OPCODE();
 }
 
+static int ZEND_FASTCALL  ZEND_ASSIGN_CLASS_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+	zend_op *opline = EX(opline);
+	zend_op *op_data = opline+1;
+
+	zend_free_op free_value;
+	zval *varname = &opline->op1.u.constant;
+	zval *value = get_zval_ptr(&op_data->op1, EX(Ts), &free_value, BP_VAR_R);
+
+	zend_std_set_static_property(EX_T(opline->op2.u.var).class_entry, Z_STRVAL_P(varname), Z_STRLEN_P(varname), &value TSRMLS_CC);
+
+	/* assign_class has two opcodes! */
+	ZEND_VM_INC_OPCODE();
+	ZEND_VM_NEXT_OPCODE();
+}
+
 static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
 	zend_op *opline = EX(opline);
@@ -3191,6 +3207,22 @@
 	ZEND_VM_NEXT_OPCODE();
 }
 
+static int ZEND_FASTCALL  ZEND_ASSIGN_CLASS_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+	zend_op *opline = EX(opline);
+	zend_op *op_data = opline+1;
+
+	zend_free_op free_value;
+	zval *varname = &opline->op1.u.constant;
+	zval *value = get_zval_ptr(&op_data->op1, EX(Ts), &free_value, BP_VAR_R);
+
+	zend_std_set_static_property(EX_T(opline->op2.u.var).class_entry, Z_STRVAL_P(varname), Z_STRLEN_P(varname), &value TSRMLS_CC);
+
+	/* assign_class has two opcodes! */
+	ZEND_VM_INC_OPCODE();
+	ZEND_VM_NEXT_OPCODE();
+}
+
 static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
 	zend_op *opline = EX(opline);
@@ -3667,6 +3699,22 @@
 	ZEND_VM_NEXT_OPCODE();
 }
 
+static int ZEND_FASTCALL  ZEND_ASSIGN_CLASS_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+	zend_op *opline = EX(opline);
+	zend_op *op_data = opline+1;
+
+	zend_free_op free_value;
+	zval *varname = &opline->op1.u.constant;
+	zval *value = get_zval_ptr(&op_data->op1, EX(Ts), &free_value, BP_VAR_R);
+
+	zend_std_set_static_property(EX_T(opline->op2.u.var).class_entry, Z_STRVAL_P(varname), Z_STRLEN_P(varname), &value TSRMLS_CC);
+
+	/* assign_class has two opcodes! */
+	ZEND_VM_INC_OPCODE();
+	ZEND_VM_NEXT_OPCODE();
+}
+
 static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
 	zend_op *opline = EX(opline);
@@ -4343,6 +4391,22 @@
 	ZEND_VM_NEXT_OPCODE();
 }
 
+static int ZEND_FASTCALL  ZEND_ASSIGN_CLASS_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+	zend_op *opline = EX(opline);
+	zend_op *op_data = opline+1;
+
+	zend_free_op free_value;
+	zval *varname = &opline->op1.u.constant;
+	zval *value = get_zval_ptr(&op_data->op1, EX(Ts), &free_value, BP_VAR_R);
+
+	zend_std_set_static_property(EX_T(opline->op2.u.var).class_entry, Z_STRVAL_P(varname), Z_STRLEN_P(varname), &value TSRMLS_CC);
+
+	/* assign_class has two opcodes! */
+	ZEND_VM_INC_OPCODE();
+	ZEND_VM_NEXT_OPCODE();
+}
+
 static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
 	zend_op *opline = EX(opline);
@@ -33671,11 +33735,11 @@
   	ZEND_ASSIGN_OBJ_SPEC_CV_VAR_HANDLER,
   	ZEND_NULL_HANDLER,
   	ZEND_ASSIGN_OBJ_SPEC_CV_CV_HANDLER,
+  	ZEND_ASSIGN_CLASS_SPEC_CONST_CONST_HANDLER,
+  	ZEND_ASSIGN_CLASS_SPEC_CONST_TMP_HANDLER,
+  	ZEND_ASSIGN_CLASS_SPEC_CONST_VAR_HANDLER,
   	ZEND_NULL_HANDLER,
-  	ZEND_NULL_HANDLER,
-  	ZEND_NULL_HANDLER,
-  	ZEND_NULL_HANDLER,
-  	ZEND_NULL_HANDLER,
+  	ZEND_ASSIGN_CLASS_SPEC_CONST_CV_HANDLER,
   	ZEND_NULL_HANDLER,
   	ZEND_NULL_HANDLER,
   	ZEND_NULL_HANDLER,
Index: zend_vm_opcodes.h
===================================================================
RCS file: /repository/ZendEngine2/zend_vm_opcodes.h,v
retrieving revision 1.42.2.17.2.1.2.7
diff -u -r1.42.2.17.2.1.2.7 zend_vm_opcodes.h
--- zend_vm_opcodes.h	14 Jul 2008 09:49:02 -0000	1.42.2.17.2.1.2.7
+++ zend_vm_opcodes.h	8 Sep 2008 09:06:36 -0000
@@ -138,6 +138,7 @@
 #define ZEND_POST_INC_OBJ                    134
 #define ZEND_POST_DEC_OBJ                    135
 #define ZEND_ASSIGN_OBJ                      136
+#define ZEND_ASSIGN_CLASS                    137
 #define ZEND_INSTANCEOF                      138
 #define ZEND_DECLARE_CLASS                   139
 #define ZEND_DECLARE_INHERITED_CLASS         140
Index: tests/get_static.phpt
===================================================================
RCS file: tests/get_static.phpt
diff -N tests/get_static.phpt
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/get_static.phpt	8 Sep 2008 09:06:37 -0000
@@ -0,0 +1,32 @@
+--TEST--
+__getStatic()
+--FILE--
+<?php
+class Regular {
+  public static $exists= TRUE;
+}
+class Base {
+  public static function __getStatic($member) {
+    var_dump($member);
+    if ('class' === $member) {
+      return new ReflectionClass(get_called_class());
+    }
+  }
+}
+class Child extends Base {
+}
+
+var_dump(Base::$class->getName());
+var_dump(Child::$class->getName());
+var_dump(Regular::$exists);
+var_dump(Regular::$nonExistant);
+?>
+===DONE===
+--EXPECTF--
+string(5) "class"
+string(4) "Base"
+string(5) "class"
+string(5) "Child"
+bool(true)
+Fatal error: Access to undeclared static property: Regular::$nonExistant in %s
+===DONE===
Index: tests/isset_static.phpt
===================================================================
RCS file: tests/isset_static.phpt
diff -N tests/isset_static.phpt
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/isset_static.phpt	8 Sep 2008 09:06:37 -0000
@@ -0,0 +1,35 @@
+--TEST--
+__issetStatic()
+--FILE--
+<?php
+class Regular {
+  public static $exists= TRUE;
+}
+class Base {
+  public static function __issetStatic($member) {
+    var_dump($member);
+    if ('class' === $member) {
+      return TRUE;
+    }
+  }
+}
+class Child extends Base {
+}
+
+var_dump(isset(Regular::$exists));
+var_dump(isset(Regular::$nonExistant));
+var_dump(isset(Base::$class));
+var_dump(isset(Child::$class));
+var_dump(isset(Base::$nonExistant));
+?>
+===DONE===
+--EXPECTF--
+bool(true)
+bool(false)
+string(5) "class"
+bool(true)
+string(5) "class"
+bool(true)
+string(11) "nonExistant"
+bool(false)
+===DONE===
Index: tests/set_static.phpt
===================================================================
RCS file: tests/set_static.phpt
diff -N tests/set_static.phpt
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/set_static.phpt	8 Sep 2008 09:06:37 -0000
@@ -0,0 +1,29 @@
+--TEST--
+__setStatic()
+--FILE--
+<?php
+class Regular {
+  public static $exists;
+}
+class Base {
+  public static function __setStatic($member, $value) {
+    var_dump($member, $value);
+  }
+}
+class Child extends Base {
+}
+
+var_dump(Regular::$exists);
+Regular::$exists= TRUE;
+var_dump(Regular::$exists);
+Base::$hello= 'World';
+Regular::$nonExistant= '@@';
+?>
+===DONE===
+--EXPECTF--
+NULL
+bool(true)
+string(5) "hello"
+string(5) "World"
+Fatal error: Cannot access undeclared property Regular::$nonExistant in %s
+===DONE===
Index: tests/unset_static.phpt
===================================================================
RCS file: tests/unset_static.phpt
diff -N tests/unset_static.phpt
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/unset_static.phpt	8 Sep 2008 09:06:37 -0000
@@ -0,0 +1,37 @@
+--TEST--
+__unsetStatic()
+--FILE--
+<?php
+class Registry {
+  public static $members= array(
+    'classes' => array('one', 'two', 'three')
+  );
+  
+  public static function __unsetStatic($member) {
+    var_dump($member);
+    unset(self::$members[$member]);
+  }
+}
+var_dump(Registry::$members);
+unset(Registry::$classes);
+var_dump(Registry::$members);
+unset(Registry::$members);
+?>
+===DONE===
+--EXPECTF--
+array(1) {
+  ["classes"]=>
+  array(3) {
+    [0]=>
+    string(3) "one"
+    [1]=>
+    string(3) "two"
+    [2]=>
+    string(5) "three"
+  }
+}
+string(7) "classes"
+array(0) {
+}
+Fatal error: Attempt to unset static property Registry::$members in %s
+===DONE===
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Apr 25 23:01:29 2024 UTC