浏览代码

Correctly attach hidden values to objects from cached templates.

Stefan Siegl 12 年之前
父节点
当前提交
ee659bdf41
共有 1 个文件被更改,包括 47 次插入41 次删除
  1. 47 41
      v8js_convert.cc

+ 47 - 41
v8js_convert.cc

@@ -319,13 +319,15 @@ static v8::Handle<v8::Value> php_v8js_hash_to_jsobj(zval *value, v8::Isolate *is
 	/* Object methods */
 	if (ce) {
 		v8::Handle<v8::FunctionTemplate> new_tpl;
+		bool cached_tpl = true;
 		static std::map<const char *, v8::Persistent<v8::FunctionTemplate> > tpl_map;
-		std::map<const char *, v8::Persistent<v8::FunctionTemplate> >::iterator it;
 
 		try {
 			new_tpl = tpl_map.at(ce->name);
 		}
 		catch (const std::out_of_range &) {
+			cached_tpl = false;
+
 			/* No cached v8::FunctionTemplate available as of yet, create one. */
 			new_tpl = v8::FunctionTemplate::New();
 
@@ -338,50 +340,53 @@ static v8::Handle<v8::Value> php_v8js_hash_to_jsobj(zval *value, v8::Isolate *is
 			} else {
 				/* Add new v8::FunctionTemplate to tpl_map, as long as it is not a closure. */
 				tpl_map[ce->name] = v8::Persistent<v8::FunctionTemplate>::New(isolate, new_tpl);
+			}
+		}
 
-				/* Attach object methods to the instance template. */
-				zend_hash_internal_pointer_reset_ex(&ce->function_table, &pos);
-				for (;; zend_hash_move_forward_ex(&ce->function_table, &pos)) {
-					if (zend_hash_get_current_key_ex(&ce->function_table, &key, &key_len, &index, 0, &pos) != HASH_KEY_IS_STRING  ||
-						zend_hash_get_current_data_ex(&ce->function_table, (void **) &method_ptr, &pos) == FAILURE
-					) {
-						break;
-					}
+		if (ce != zend_ce_closure) {
+			/* Attach object methods to the instance template. */
+			zend_hash_internal_pointer_reset_ex(&ce->function_table, &pos);
+			for (;; zend_hash_move_forward_ex(&ce->function_table, &pos)) {
+				if (zend_hash_get_current_key_ex(&ce->function_table, &key, &key_len, &index, 0, &pos) != HASH_KEY_IS_STRING  ||
+					zend_hash_get_current_data_ex(&ce->function_table, (void **) &method_ptr, &pos) == FAILURE
+				) {
+					break;
+				}
 
-					if ((method_ptr->common.fn_flags & ZEND_ACC_PUBLIC)     && /* Allow only public methods */
-						(method_ptr->common.fn_flags & ZEND_ACC_CTOR) == 0  && /* ..and no __construct() */
-						(method_ptr->common.fn_flags & ZEND_ACC_DTOR) == 0  && /* ..or __destruct() */
-						(method_ptr->common.fn_flags & ZEND_ACC_CLONE) == 0 /* ..or __clone() functions */
+				if ((method_ptr->common.fn_flags & ZEND_ACC_PUBLIC)     && /* Allow only public methods */
+					(method_ptr->common.fn_flags & ZEND_ACC_CTOR) == 0  && /* ..and no __construct() */
+					(method_ptr->common.fn_flags & ZEND_ACC_DTOR) == 0  && /* ..or __destruct() */
+					(method_ptr->common.fn_flags & ZEND_ACC_CLONE) == 0 /* ..or __clone() functions */
+				) {
+					/* Override native toString() with __tostring() if it is set in passed object */
+					if (!cached_tpl && IS_MAGIC_FUNC(ZEND_TOSTRING_FUNC_NAME)) {
+						new_tpl->InstanceTemplate()->Set(V8JS_SYM("toString"), PHP_V8JS_CALLBACK(method_ptr));
+					/* TODO: __set(), __unset() disabled as JS is not allowed to modify the passed PHP object yet.
+					 *  __sleep(), __wakeup(), __set_state() are always ignored */
+					} else if (
+						IS_MAGIC_FUNC(ZEND_CALLSTATIC_FUNC_NAME)|| /* TODO */
+						IS_MAGIC_FUNC(ZEND_SLEEP_FUNC_NAME)     ||
+						IS_MAGIC_FUNC(ZEND_WAKEUP_FUNC_NAME)    ||
+						IS_MAGIC_FUNC(ZEND_SET_STATE_FUNC_NAME) ||
+						IS_MAGIC_FUNC(ZEND_SET_FUNC_NAME)       ||
+						IS_MAGIC_FUNC(ZEND_UNSET_FUNC_NAME)
 					) {
-						/* Override native toString() with __tostring() if it is set in passed object */
-						if (IS_MAGIC_FUNC(ZEND_TOSTRING_FUNC_NAME)) {
-							new_tpl->InstanceTemplate()->Set(V8JS_SYM("toString"), PHP_V8JS_CALLBACK(method_ptr));
-						/* TODO: __set(), __unset() disabled as JS is not allowed to modify the passed PHP object yet.
-						 *  __sleep(), __wakeup(), __set_state() are always ignored */
-						} else if (
-							IS_MAGIC_FUNC(ZEND_CALLSTATIC_FUNC_NAME)|| /* TODO */
-							IS_MAGIC_FUNC(ZEND_SLEEP_FUNC_NAME)     ||
-							IS_MAGIC_FUNC(ZEND_WAKEUP_FUNC_NAME)    ||
-							IS_MAGIC_FUNC(ZEND_SET_STATE_FUNC_NAME) ||
-							IS_MAGIC_FUNC(ZEND_SET_FUNC_NAME)       ||
-							IS_MAGIC_FUNC(ZEND_UNSET_FUNC_NAME)
-						) {
-						/* Register all magic function as hidden with lowercase name */
-						} else if (IS_MAGIC_FUNC(ZEND_GET_FUNC_NAME)) {
-							get_ptr = method_ptr;
-						} else if (IS_MAGIC_FUNC(ZEND_CALL_FUNC_NAME)) {
-							call_ptr = method_ptr;
-						} else if (IS_MAGIC_FUNC(ZEND_INVOKE_FUNC_NAME)) {
-							invoke_ptr = method_ptr;
-						} else if (IS_MAGIC_FUNC(ZEND_ISSET_FUNC_NAME)) {
-							isset_ptr = method_ptr;
-						} else {
-							new_tpl->InstanceTemplate()->Set(V8JS_STR(method_ptr->common.function_name), PHP_V8JS_CALLBACK(method_ptr), v8::ReadOnly);
-						}
+					/* Register all magic function as hidden with lowercase name */
+					} else if (IS_MAGIC_FUNC(ZEND_GET_FUNC_NAME)) {
+						get_ptr = method_ptr;
+					} else if (IS_MAGIC_FUNC(ZEND_CALL_FUNC_NAME)) {
+						call_ptr = method_ptr;
+					} else if (IS_MAGIC_FUNC(ZEND_INVOKE_FUNC_NAME)) {
+						invoke_ptr = method_ptr;
+					} else if (IS_MAGIC_FUNC(ZEND_ISSET_FUNC_NAME)) {
+						isset_ptr = method_ptr;
+					} else if (!cached_tpl) {
+						new_tpl->InstanceTemplate()->Set(V8JS_STR(method_ptr->common.function_name), PHP_V8JS_CALLBACK(method_ptr), v8::ReadOnly);
 					}
 				}
+			}
 
-
+			if (!cached_tpl) {
 				/* Only register getter, etc. when they're set in PHP side */
 				if (call_ptr || get_ptr || isset_ptr)
 				{
@@ -396,7 +401,6 @@ static v8::Handle<v8::Value> php_v8js_hash_to_jsobj(zval *value, v8::Isolate *is
 					);
 				}
 
-
 				/* __invoke() handler */
 				if (invoke_ptr) {
 					new_tpl->InstanceTemplate()->SetCallAsFunctionHandler(php_v8js_property_caller, V8JS_SYM(ZEND_INVOKE_FUNC_NAME));
@@ -416,7 +420,9 @@ static v8::Handle<v8::Value> php_v8js_hash_to_jsobj(zval *value, v8::Isolate *is
 
 		newobj = persist_newobj;
 
-		if (ce != zend_ce_closure) {	// @fixme all of those get lost, when using cached templates
+		if (ce != zend_ce_closure) {
+			// These unfortunately cannot be attached to the template, hence we have to put them
+			// on each and every object instance manually.
 			if (call_ptr) {
 				newobj->SetHiddenValue(V8JS_SYM(ZEND_CALL_FUNC_NAME), PHP_V8JS_CALLBACK(call_ptr));
 			}