فهرست منبع

Split php_v8js_hash_to_jsobj into smaller pieces

php_v8js_hash_to_jsobj is called for all wrapping to JS objects, be it
a PHP associative array or a PHP object.  I've now splitted both parts
into seperate functions since they don't share any code any longer
anyways.
Stefan Siegl 10 سال پیش
والد
کامیت
02d8ecc16e
1فایلهای تغییر یافته به همراه132 افزوده شده و 106 حذف شده
  1. 132 106
      v8js_object_export.cc

+ 132 - 106
v8js_object_export.cc

@@ -841,130 +841,95 @@ static void php_v8js_named_property_deleter(v8::Local<v8::String> property, cons
 }
 /* }}} */
 
-v8::Handle<v8::Value> php_v8js_hash_to_jsobj(zval *value, v8::Isolate *isolate TSRMLS_DC) /* {{{ */
-{
-	v8::Handle<v8::Object> newobj;
-	int i;
-	char *key = NULL;
-	ulong index;
-	uint key_len;
-	HashTable *myht;
-	HashPosition pos;
-	zend_class_entry *ce = NULL;
 
-	if (Z_TYPE_P(value) == IS_ARRAY) {
-		myht = HASH_OF(value);
-	} else {
-		myht = Z_OBJPROP_P(value);
-		ce = Z_OBJCE_P(value);
-	}
 
-	/* Prevent recursion */
-	if (myht && myht->nApplyCount > 1) {
-		return V8JS_NULL;
+static v8::Handle<v8::Object> php_v8js_wrap_object(v8::Isolate *isolate, zend_class_entry *ce, zval *value) /* {{{ */
+{
+	php_v8js_ctx *ctx = (php_v8js_ctx *) isolate->GetData(0);
+	v8::Local<v8::FunctionTemplate> new_tpl;
+	v8js_tmpl_t *persist_tpl_;
+
+	try {
+		new_tpl = v8::Local<v8::FunctionTemplate>::New
+			(isolate, ctx->template_cache.at(ce->name));
 	}
+	catch (const std::out_of_range &) {
+		/* No cached v8::FunctionTemplate available as of yet, create one. */
+		new_tpl = v8::FunctionTemplate::New(isolate, 0);
 
-	/* Check for ArrayAccess object */
-	if (V8JSG(use_array_access) && ce) {
-		bool has_array_access = false;
-		bool has_countable = false;
+		new_tpl->SetClassName(V8JS_STRL(ce->name, ce->name_length));
+		new_tpl->InstanceTemplate()->SetInternalFieldCount(1);
 
-		for (int i = 0; i < ce->num_interfaces; i ++) {
-			if (strcmp (ce->interfaces[i]->name, "ArrayAccess") == 0) {
-				has_array_access = true;
-			}
-			else if (strcmp (ce->interfaces[i]->name, "Countable") == 0) {
-				has_countable = true;
+		if (ce == zend_ce_closure) {
+			/* Got a closure, mustn't cache ... */
+			persist_tpl_ = new v8js_tmpl_t(isolate, new_tpl);
+			/* We'll free persist_tpl_ via php_v8js_weak_closure_callback, below */
+			new_tpl->InstanceTemplate()->SetCallAsFunctionHandler(php_v8js_php_callback);
+		} else {
+			/* Add new v8::FunctionTemplate to tpl_map, as long as it is not a closure. */
+			persist_tpl_ = &ctx->template_cache[ce->name];
+			persist_tpl_->Reset(isolate, new_tpl);
+			/* We'll free persist_tpl_ when template_cache is destroyed */
+			// Finish setup of new_tpl
+			new_tpl->InstanceTemplate()->SetNamedPropertyHandler
+				(php_v8js_named_property_getter, /* getter */
+				 php_v8js_named_property_setter, /* setter */
+				 php_v8js_named_property_query, /* query */
+				 php_v8js_named_property_deleter, /* deleter */
+				 php_v8js_named_property_enumerator, /* enumerator */
+				 V8JS_NULL /* data */
+				 );
+			// add __invoke() handler
+			zend_function *invoke_method_ptr;
+			if (zend_hash_find(&ce->function_table, ZEND_INVOKE_FUNC_NAME,
+							   sizeof(ZEND_INVOKE_FUNC_NAME),
+							   (void**)&invoke_method_ptr) == SUCCESS &&
+				invoke_method_ptr->common.fn_flags & ZEND_ACC_PUBLIC) {
+				new_tpl->InstanceTemplate()->SetCallAsFunctionHandler(php_v8js_invoke_callback, PHP_V8JS_CALLBACK(isolate, invoke_method_ptr, new_tpl));
 			}
 		}
-
-		if(has_array_access && has_countable) {
-			return php_v8js_array_access_to_jsobj(value, isolate TSRMLS_CC);
-		}
+		v8::Local<v8::Array> call_handler_data = v8::Array::New(isolate, 2);
+		call_handler_data->Set(0, v8::External::New(isolate, persist_tpl_));
+		call_handler_data->Set(1, v8::External::New(isolate, ce));
+		new_tpl->SetCallHandler(php_v8js_construct_callback, call_handler_data);
 	}
 
-	/* Object methods */
-	if (ce == php_ce_v8_function) {
-		php_v8js_object *c = (php_v8js_object *) zend_object_store_get_object(value TSRMLS_CC);
+	// Create v8 wrapper object
+	v8::Handle<v8::Value> external = v8::External::New(isolate, value);
+	v8::Handle<v8::Object> newobj = new_tpl->GetFunction()->NewInstance(1, &external);
 
-		if(isolate != c->ctx->isolate) {
-			php_error_docref(NULL TSRMLS_CC, E_WARNING, "V8Function object passed to wrong V8Js instance");
-			return V8JS_NULL;
-		}
+	if (ce == zend_ce_closure) {
+		// free uncached function template when object is freed
+		ctx->weak_closures[persist_tpl_].Reset(isolate, newobj);
+		ctx->weak_closures[persist_tpl_].SetWeak(persist_tpl_, php_v8js_weak_closure_callback);
+	}
 
-		v8::Local<v8::Value> v8obj = v8::Local<v8::Value>::New(isolate, c->v8obj);
-		return v8obj;
-	} else if (ce) {
-		php_v8js_ctx *ctx = (php_v8js_ctx *) isolate->GetData(0);
-		v8::Local<v8::FunctionTemplate> new_tpl;
-		v8js_tmpl_t *persist_tpl_;
+	return newobj;
+}
+/* }}} */
 
-		try {
-			new_tpl = v8::Local<v8::FunctionTemplate>::New
-				(isolate, ctx->template_cache.at(ce->name));
-		}
-		catch (const std::out_of_range &) {
-			/* No cached v8::FunctionTemplate available as of yet, create one. */
-			new_tpl = v8::FunctionTemplate::New(isolate, 0);
-
-			new_tpl->SetClassName(V8JS_STRL(ce->name, ce->name_length));
-			new_tpl->InstanceTemplate()->SetInternalFieldCount(1);
-
-			if (ce == zend_ce_closure) {
-				/* Got a closure, mustn't cache ... */
-				persist_tpl_ = new v8js_tmpl_t(isolate, new_tpl);
-				/* We'll free persist_tpl_ via php_v8js_weak_closure_callback, below */
-				new_tpl->InstanceTemplate()->SetCallAsFunctionHandler(php_v8js_php_callback);
-			} else {
-				/* Add new v8::FunctionTemplate to tpl_map, as long as it is not a closure. */
-				persist_tpl_ = &ctx->template_cache[ce->name];
-				persist_tpl_->Reset(isolate, new_tpl);
-				/* We'll free persist_tpl_ when template_cache is destroyed */
-				// Finish setup of new_tpl
-				new_tpl->InstanceTemplate()->SetNamedPropertyHandler
-					(php_v8js_named_property_getter, /* getter */
-					 php_v8js_named_property_setter, /* setter */
-					 php_v8js_named_property_query, /* query */
-					 php_v8js_named_property_deleter, /* deleter */
-					 php_v8js_named_property_enumerator, /* enumerator */
-					 V8JS_NULL /* data */
-					 );
-				// add __invoke() handler
-				zend_function *invoke_method_ptr;
-				if (zend_hash_find(&ce->function_table, ZEND_INVOKE_FUNC_NAME,
-								   sizeof(ZEND_INVOKE_FUNC_NAME),
-								   (void**)&invoke_method_ptr) == SUCCESS &&
-					invoke_method_ptr->common.fn_flags & ZEND_ACC_PUBLIC) {
-					new_tpl->InstanceTemplate()->SetCallAsFunctionHandler(php_v8js_invoke_callback, PHP_V8JS_CALLBACK(isolate, invoke_method_ptr, new_tpl));
-				}
-			}
-			v8::Local<v8::Array> call_handler_data = v8::Array::New(isolate, 2);
-			call_handler_data->Set(0, v8::External::New(isolate, persist_tpl_));
-			call_handler_data->Set(1, v8::External::New(isolate, ce));
-			new_tpl->SetCallHandler(php_v8js_construct_callback, call_handler_data);
-		}
 
-		// Create v8 wrapper object
-		v8::Handle<v8::Value> external = v8::External::New(isolate, value);
-		newobj = new_tpl->GetFunction()->NewInstance(1, &external);
+v8::Handle<v8::Object> php_v8js_wrap_array_to_object(v8::Isolate *isolate, zval *value) /* {{{ */
+{
+	int i;
+	HashPosition pos;
+	char *key = NULL;
+	uint key_len;
+	ulong index;
 
-		if (ce == zend_ce_closure) {
-			// free uncached function template when object is freed
-			ctx->weak_closures[persist_tpl_].Reset(isolate, newobj);
-			ctx->weak_closures[persist_tpl_].SetWeak(persist_tpl_, php_v8js_weak_closure_callback);
-		}
-	} else {
-		// @todo re-use template likewise
-		v8::Local<v8::FunctionTemplate> new_tpl = v8::FunctionTemplate::New(isolate, 0);
+	// @todo re-use template likewise
+	v8::Local<v8::FunctionTemplate> new_tpl = v8::FunctionTemplate::New(isolate, 0);
 
-		new_tpl->SetClassName(V8JS_SYM("Array"));
-		newobj = new_tpl->InstanceTemplate()->NewInstance();
-	}
+	/* Call it Array, but it is not a native array, especially it doesn't have
+	 * have the typical Array.prototype functions. */
+	new_tpl->SetClassName(V8JS_SYM("Array"));
+
+	v8::Handle<v8::Object> newobj = new_tpl->InstanceTemplate()->NewInstance();
 
-	/* Object properties */
+	HashTable *myht = HASH_OF(value);
 	i = myht ? zend_hash_num_elements(myht) : 0;
 
-	if (i > 0 && !ce)
+	if (i > 0)
 	{
 		zval **data;
 		HashTable *tmp_ht;
@@ -1003,10 +968,71 @@ v8::Handle<v8::Value> php_v8js_hash_to_jsobj(zval *value, v8::Isolate *isolate T
 			}
 		}
 	}
+
 	return newobj;
 }
 /* }}} */
 
+
+v8::Handle<v8::Value> php_v8js_hash_to_jsobj(zval *value, v8::Isolate *isolate TSRMLS_DC) /* {{{ */
+{
+	HashTable *myht;
+	zend_class_entry *ce = NULL;
+
+	if (Z_TYPE_P(value) == IS_ARRAY) {
+		myht = HASH_OF(value);
+	} else {
+		myht = Z_OBJPROP_P(value);
+		ce = Z_OBJCE_P(value);
+	}
+
+	/* Prevent recursion */
+	if (myht && myht->nApplyCount > 1) {
+		return V8JS_NULL;
+	}
+
+	/* Check for ArrayAccess object */
+	if (V8JSG(use_array_access) && ce) {
+		bool has_array_access = false;
+		bool has_countable = false;
+
+		for (int i = 0; i < ce->num_interfaces; i ++) {
+			if (strcmp (ce->interfaces[i]->name, "ArrayAccess") == 0) {
+				has_array_access = true;
+			}
+			else if (strcmp (ce->interfaces[i]->name, "Countable") == 0) {
+				has_countable = true;
+			}
+		}
+
+		if(has_array_access && has_countable) {
+			return php_v8js_array_access_to_jsobj(value, isolate TSRMLS_CC);
+		}
+	}
+
+	/* Special case, passing back object originating from JS to JS */
+	if (ce == php_ce_v8_function) {
+		php_v8js_object *c = (php_v8js_object *) zend_object_store_get_object(value TSRMLS_CC);
+
+		if(isolate != c->ctx->isolate) {
+			php_error_docref(NULL TSRMLS_CC, E_WARNING, "V8Function object passed to wrong V8Js instance");
+			return V8JS_NULL;
+		}
+
+		return v8::Local<v8::Value>::New(isolate, c->v8obj);
+	}
+
+	/* If it's a PHP object, wrap it */
+	if (ce) {
+		return php_v8js_wrap_object(isolate, ce, value);
+	}
+
+	/* Associative PHP arrays cannot be wrapped to JS arrays, convert them to
+	 * JS objects and attach all their array keys as properties. */
+	return php_v8js_wrap_array_to_object(isolate, value);
+}
+/* }}} */
+
 /*
  * Local variables:
  * tab-width: 4