Browse Source

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 years ago
parent
commit
02d8ecc16e
1 changed files with 132 additions and 106 deletions
  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