Browse Source

Allow PHP exception to JS propagation

Stefan Siegl 9 years ago
parent
commit
462eb623b3
4 changed files with 51 additions and 8 deletions
  1. 1 0
      php_v8js_macros.h
  2. 36 0
      tests/php_exceptions_003.phpt
  3. 1 0
      v8js_class.cc
  4. 13 8
      v8js_object_export.cc

+ 1 - 0
php_v8js_macros.h

@@ -83,6 +83,7 @@ extern "C" {
 /* Options */
 #define V8JS_FLAG_NONE			(1<<0)
 #define V8JS_FLAG_FORCE_ARRAY	(1<<1)
+#define V8JS_FLAG_PROPAGATE_PHP_EXCEPTIONS	(1<<2)
 
 #define V8JS_DEBUG_AUTO_BREAK_NEVER		0
 #define V8JS_DEBUG_AUTO_BREAK_ONCE		1

+ 36 - 0
tests/php_exceptions_003.phpt

@@ -0,0 +1,36 @@
+--TEST--
+Test V8::executeString() : PHP Exception handling (basic JS propagation)
+--SKIPIF--
+<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?>
+--FILE--
+<?php
+
+class Foo {
+    function throwException() {
+	throw new \Exception("Test-Exception");
+    }
+}
+
+$v8 = new V8Js();
+$v8->foo = new \Foo();
+
+$JS = <<< EOT
+try {
+    PHP.foo.throwException();
+    // the exception should abort further execution,
+    // hence the print must not pop up
+    print("after throwException\\n");
+} catch(e) {
+    print("JS caught exception!\\n");
+    var_dump(e.getMessage());
+}
+EOT;
+
+$v8->executeString($JS, 'php_exceptions_003', V8Js::FLAG_PROPAGATE_PHP_EXCEPTIONS);
+
+?>
+===EOF===
+--EXPECTF--
+JS caught exception!
+string(14) "Test-Exception"
+===EOF===

+ 1 - 0
v8js_class.cc

@@ -1078,6 +1078,7 @@ PHP_MINIT_FUNCTION(v8js_class) /* {{{ */
 
 	zend_declare_class_constant_long(php_ce_v8js, ZEND_STRL("FLAG_NONE"),			V8JS_FLAG_NONE			TSRMLS_CC);
 	zend_declare_class_constant_long(php_ce_v8js, ZEND_STRL("FLAG_FORCE_ARRAY"),	V8JS_FLAG_FORCE_ARRAY	TSRMLS_CC);
+	zend_declare_class_constant_long(php_ce_v8js, ZEND_STRL("FLAG_PROPAGATE_PHP_EXCEPTIONS"), V8JS_FLAG_PROPAGATE_PHP_EXCEPTIONS TSRMLS_CC);
 
 #ifdef ENABLE_DEBUGGER_SUPPORT
 	zend_declare_class_constant_long(php_ce_v8js, ZEND_STRL("DEBUG_AUTO_BREAK_NEVER"),	V8JS_DEBUG_AUTO_BREAK_NEVER			TSRMLS_CC);

+ 13 - 8
v8js_object_export.cc

@@ -21,6 +21,7 @@ extern "C" {
 #include "ext/standard/php_string.h"
 #include "zend_interfaces.h"
 #include "zend_closures.h"
+#include "zend_exceptions.h"
 }
 
 #include "php_v8js_macros.h"
@@ -33,7 +34,7 @@ static void v8js_weak_object_callback(const v8::WeakCallbackData<v8::Object, zva
 /* Callback for PHP methods and functions */
 static void v8js_call_php_func(zval *value, zend_class_entry *ce, zend_function *method_ptr, v8::Isolate *isolate, const v8::FunctionCallbackInfo<v8::Value>& info TSRMLS_DC) /* {{{ */
 {
-	v8::Handle<v8::Value> return_value;
+	v8::Handle<v8::Value> return_value = V8JS_NULL;
 	zend_fcall_info fci;
 	zend_fcall_info_cache fcc;
 	zval fname, *retval_ptr = NULL, **argv = NULL;
@@ -138,10 +139,6 @@ static void v8js_call_php_func(zval *value, zend_class_entry *ce, zend_function
 	}
 	zend_end_try();
 
-	if(EG(exception)) {
-		v8js_terminate_execution(isolate);
-	}
-
 failure:
 	/* Cleanup */
 	if (argc) {
@@ -152,11 +149,19 @@ failure:
 		efree(fci.params);
 	}
 
-	if (retval_ptr != NULL) {
+	if(EG(exception)) {
+		if(ctx->flags & V8JS_FLAG_PROPAGATE_PHP_EXCEPTIONS) {
+			return_value = isolate->ThrowException(zval_to_v8js(EG(exception), isolate TSRMLS_CC));
+			zend_clear_exception(TSRMLS_C);
+		} else {
+			v8js_terminate_execution(isolate);
+		}
+	} else if (retval_ptr != NULL) {
 		return_value = zval_to_v8js(retval_ptr, isolate TSRMLS_CC);
+	}
+
+	if (retval_ptr != NULL) {
 		zval_ptr_dtor(&retval_ptr);
-	} else {
-		return_value = V8JS_NULL;
 	}
 
 	info.GetReturnValue().Set(return_value);