Browse Source

Merge pull request #186 from stesie/issue-185

Provide correct "this" on V8Object method invocation, closes #185
Stefan Siegl 9 years ago
parent
commit
61febfb589
4 changed files with 107 additions and 1 deletions
  1. 36 0
      tests/issue_185_001.phpt
  2. 28 0
      tests/issue_185_002.phpt
  3. 32 0
      tests/issue_185_basic.phpt
  4. 11 1
      v8js_v8object_class.cc

+ 36 - 0
tests/issue_185_001.phpt

@@ -0,0 +1,36 @@
+--TEST--
+Test V8::executeString() : Issue #185 this on direct invocation of method
+--SKIPIF--
+<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?>
+--FILE--
+<?php
+
+$v8 = new V8Js();
+
+$JS = <<<EOT
+
+function Bar(i) {
+    this.theValue = i;
+}
+Bar.prototype.tell = function() {
+    var_dump(this.theValue);
+    var_dump(typeof this.exit);
+};
+var inst = new Bar(23);
+var fn = inst.tell;
+fn();
+EOT;
+
+$v8->executeString($JS);
+
+// now fetch `inst` from V8 and call method from PHP
+$fn = $v8->executeString('(inst.tell)');
+$fn();
+?>
+===EOF===
+--EXPECT--
+NULL
+string(8) "function"
+NULL
+string(8) "function"
+===EOF===

+ 28 - 0
tests/issue_185_002.phpt

@@ -0,0 +1,28 @@
+--TEST--
+Test V8::executeString() : Issue #185 this on function invocation
+--SKIPIF--
+<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?>
+--FILE--
+<?php
+
+$v8 = new V8Js();
+
+$JS = <<<EOT
+
+function fn() {
+    var_dump(typeof this.exit);
+};
+fn();
+EOT;
+
+$v8->executeString($JS);
+
+// now fetch `inst` from V8 and call method from PHP
+$fn = $v8->executeString('(fn)');
+$fn();
+?>
+===EOF===
+--EXPECT--
+string(8) "function"
+string(8) "function"
+===EOF===

+ 32 - 0
tests/issue_185_basic.phpt

@@ -0,0 +1,32 @@
+--TEST--
+Test V8::executeString() : Issue #185 Wrong this on V8Object method invocation
+--SKIPIF--
+<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?>
+--FILE--
+<?php
+
+$v8 = new V8Js();
+
+$JS = <<<EOT
+
+function Bar(i) {
+    this.theValue = i;
+}
+Bar.prototype.tell = function() {
+    var_dump(this.theValue);
+};
+var inst = new Bar(23);
+inst.tell();
+EOT;
+
+$v8->executeString($JS);
+
+// now fetch `inst` from V8 and call method from PHP
+$inst = $v8->executeString('(inst)');
+$inst->tell();
+?>
+===EOF===
+--EXPECT--
+int(23)
+int(23)
+===EOF===

+ 11 - 1
v8js_v8object_class.cc

@@ -302,6 +302,7 @@ static int v8js_v8object_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS)
 
 
 		v8::Local<v8::String> method_name = V8JS_SYML(method, strlen(method));
 		v8::Local<v8::String> method_name = V8JS_SYML(method, strlen(method));
 		v8::Local<v8::Object> v8obj = v8::Local<v8::Value>::New(isolate, obj->v8obj)->ToObject();
 		v8::Local<v8::Object> v8obj = v8::Local<v8::Value>::New(isolate, obj->v8obj)->ToObject();
+		v8::Local<v8::Object> thisObj;
 		v8::Local<v8::Function> cb;
 		v8::Local<v8::Function> cb;
 
 
 		if (method_name->Equals(V8JS_SYM(V8JS_V8_INVOKE_FUNC_NAME))) {
 		if (method_name->Equals(V8JS_SYM(V8JS_V8_INVOKE_FUNC_NAME))) {
@@ -310,6 +311,15 @@ static int v8js_v8object_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS)
 			cb = v8::Local<v8::Function>::Cast(v8obj->Get(method_name));
 			cb = v8::Local<v8::Function>::Cast(v8obj->Get(method_name));
 		}
 		}
 
 
+		// If a method is invoked on V8Object, then set the object itself as
+		// "this" on JS side.  Otherwise fall back to global object.
+		if (obj->std.ce == php_ce_v8object) {
+			thisObj = v8obj;
+		}
+		else {
+			thisObj = V8JS_GLOBAL(isolate);
+		}
+
 		v8::Local<v8::Value> *jsArgv = static_cast<v8::Local<v8::Value> *>(alloca(sizeof(v8::Local<v8::Value>) * argc));
 		v8::Local<v8::Value> *jsArgv = static_cast<v8::Local<v8::Value> *>(alloca(sizeof(v8::Local<v8::Value>) * argc));
 		v8::Local<v8::Value> js_retval;
 		v8::Local<v8::Value> js_retval;
 
 
@@ -318,7 +328,7 @@ static int v8js_v8object_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS)
 			jsArgv[i] = v8::Local<v8::Value>::New(isolate, zval_to_v8js(*argv[i], isolate TSRMLS_CC));
 			jsArgv[i] = v8::Local<v8::Value>::New(isolate, zval_to_v8js(*argv[i], isolate TSRMLS_CC));
 		}
 		}
 
 
-		return cb->Call(V8JS_GLOBAL(isolate), argc, jsArgv);
+		return cb->Call(thisObj, argc, jsArgv);
 	};
 	};
 
 
 	v8js_v8_call(obj->ctx, &return_value, obj->flags, obj->ctx->time_limit, obj->ctx->memory_limit, v8_call TSRMLS_CC);
 	v8js_v8_call(obj->ctx, &return_value, obj->flags, obj->ctx->time_limit, obj->ctx->memory_limit, v8_call TSRMLS_CC);