Skip to content
This repository was archived by the owner on Mar 29, 2024. It is now read-only.

Commit 52bdee0

Browse files
authored
Merge pull request #29 from pinepain/improve-exceptions-api
Improve exceptions api
2 parents 16307fd + dde27ce commit 52bdee0

11 files changed

+231
-46
lines changed

src/php_v8_exception.cc

+5-5
Original file line numberDiff line numberDiff line change
@@ -191,27 +191,27 @@ static PHP_METHOD(V8Exception, GetStackTrace) {
191191
}
192192

193193

194-
PHP_V8_ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_v8_exception_RangeError, ZEND_RETURN_VALUE, 2, V8\\Value, 0)
194+
PHP_V8_ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_v8_exception_RangeError, ZEND_RETURN_VALUE, 2, V8\\ObjectValue, 0)
195195
ZEND_ARG_OBJ_INFO(0, context, V8\\Context, 0)
196196
ZEND_ARG_OBJ_INFO(0, message, V8\\StringValue, 0)
197197
ZEND_END_ARG_INFO()
198198

199-
PHP_V8_ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_v8_exception_ReferenceError, ZEND_RETURN_VALUE, 2, V8\\Value, 0)
199+
PHP_V8_ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_v8_exception_ReferenceError, ZEND_RETURN_VALUE, 2, V8\\ObjectValue, 0)
200200
ZEND_ARG_OBJ_INFO(0, context, V8\\Context, 0)
201201
ZEND_ARG_OBJ_INFO(0, message, V8\\StringValue, 0)
202202
ZEND_END_ARG_INFO()
203203

204-
PHP_V8_ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_v8_exception_SyntaxError, ZEND_RETURN_VALUE, 2, V8\\Value, 0)
204+
PHP_V8_ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_v8_exception_SyntaxError, ZEND_RETURN_VALUE, 2, V8\\ObjectValue, 0)
205205
ZEND_ARG_OBJ_INFO(0, context, V8\\Context, 0)
206206
ZEND_ARG_OBJ_INFO(0, message, V8\\StringValue, 0)
207207
ZEND_END_ARG_INFO()
208208

209-
PHP_V8_ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_v8_exception_TypeError, ZEND_RETURN_VALUE, 2, V8\\Value, 0)
209+
PHP_V8_ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_v8_exception_TypeError, ZEND_RETURN_VALUE, 2, V8\\ObjectValue, 0)
210210
ZEND_ARG_OBJ_INFO(0, context, V8\\Context, 0)
211211
ZEND_ARG_OBJ_INFO(0, message, V8\\StringValue, 0)
212212
ZEND_END_ARG_INFO()
213213

214-
PHP_V8_ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_v8_exception_Error, ZEND_RETURN_VALUE, 2, V8\\Value, 0)
214+
PHP_V8_ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_v8_exception_Error, ZEND_RETURN_VALUE, 2, V8\\ObjectValue, 0)
215215
ZEND_ARG_OBJ_INFO(0, context, V8\\Context, 0)
216216
ZEND_ARG_OBJ_INFO(0, message, V8\\StringValue, 0)
217217
ZEND_END_ARG_INFO()

src/php_v8_isolate.cc

+20-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "php_v8_context.h"
2222
#include "php_v8_exceptions.h"
2323
#include "php_v8_stack_trace.h"
24+
#include "php_v8_object.h"
2425
#include "php_v8_value.h"
2526
#include "php_v8_a.h"
2627
#include "php_v8.h"
@@ -346,8 +347,9 @@ static PHP_METHOD(V8Isolate, GetEnteredContext) {
346347
static PHP_METHOD(V8Isolate, ThrowException) {
347348
zval *php_v8_context_zv;
348349
zval *php_v8_value_zv;
350+
zval *exception_zv = NULL;
349351

350-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "oo", &php_v8_context_zv, &php_v8_value_zv) == FAILURE) {
352+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "oo|o", &php_v8_context_zv, &php_v8_value_zv, &exception_zv) == FAILURE) {
351353
return;
352354
}
353355

@@ -364,6 +366,22 @@ static PHP_METHOD(V8Isolate, ThrowException) {
364366

365367
v8::Local<v8::Value> local_value = php_v8_value_get_local(php_v8_value);
366368

369+
if (NULL != exception_zv) {
370+
if (!local_value->IsObject()) {
371+
PHP_V8_THROW_VALUE_EXCEPTION("Unable to associate external exception with non-object value");
372+
return;
373+
}
374+
375+
php_v8_value_t *php_v8_value = php_v8_object_get_self_ptr(php_v8_isolate, local_value.As<v8::Object>());
376+
377+
if (!Z_ISUNDEF(php_v8_value->exception)) {
378+
PHP_V8_THROW_VALUE_EXCEPTION("Another external exception is already associated with a given value");
379+
return;
380+
}
381+
382+
ZVAL_COPY(&php_v8_value->exception, exception_zv);
383+
}
384+
367385
isolate->ThrowException(local_value);
368386
}
369387

@@ -505,6 +523,7 @@ ZEND_END_ARG_INFO()
505523
ZEND_BEGIN_ARG_INFO_EX(arginfo_v8_isolate_ThrowException, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 2)
506524
ZEND_ARG_OBJ_INFO(0, context, V8\\Context, 0)
507525
ZEND_ARG_OBJ_INFO(0, value, V8\\Value, 0)
526+
ZEND_ARG_OBJ_INFO(0, e, Throwable, 0)
508527
ZEND_END_ARG_INFO()
509528

510529
PHP_V8_ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_v8_isolate_IdleNotificationDeadline, ZEND_RETURN_VALUE, 1, _IS_BOOL, 0)

src/php_v8_try_catch.cc

+36-3
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,15 @@ void php_v8_try_catch_create_from_try_catch(zval *return_value, php_v8_isolate_t
4343

4444
if (try_catch && !try_catch->Exception().IsEmpty()) {
4545
zval exception_zv;
46-
php_v8_get_or_create_value(&exception_zv, try_catch->Exception(), php_v8_isolate);
46+
php_v8_value_t * php_v8_value = php_v8_get_or_create_value(&exception_zv, try_catch->Exception(), php_v8_isolate);
4747
zend_update_property(this_ce, return_value, ZEND_STRL("exception"), &exception_zv);
48+
49+
if (!Z_ISUNDEF(php_v8_value->exception)) {
50+
zend_update_property(this_ce, return_value, ZEND_STRL("external_exception"), &php_v8_value->exception);
51+
zval_ptr_dtor(&php_v8_value->exception);
52+
ZVAL_UNDEF(&php_v8_value->exception);
53+
}
54+
4855
zval_ptr_dtor(&exception_zv);
4956
}
5057

@@ -71,18 +78,20 @@ static PHP_METHOD(V8TryCatch, __construct) {
7178
zval *php_v8_exception_zv = NULL;
7279
zval *php_v8_stack_trace_zv = NULL;
7380
zval *php_v8_message_zv = NULL;
81+
zval *external_exception_zv = NULL;
7482

7583
zend_bool can_continue = '\0';
7684
zend_bool has_terminated = '\0';
7785

78-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "oo|o!o!o!bb",
86+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "oo|o!o!o!bbo!",
7987
&php_v8_isolate_zv,
8088
&php_v8_context_zv,
8189
&php_v8_exception_zv,
8290
&php_v8_stack_trace_zv,
8391
&php_v8_message_zv,
8492
&can_continue,
85-
&has_terminated) == FAILURE) {
93+
&has_terminated,
94+
&external_exception_zv) == FAILURE) {
8695
return;
8796
}
8897

@@ -114,6 +123,10 @@ static PHP_METHOD(V8TryCatch, __construct) {
114123

115124
zend_update_property_bool(this_ce, getThis(), ZEND_STRL("can_continue"), can_continue);
116125
zend_update_property_bool(this_ce, getThis(), ZEND_STRL("has_terminated"), has_terminated);
126+
127+
if (external_exception_zv != NULL) {
128+
zend_update_property(this_ce, getThis(), ZEND_STRL("external_exception"), external_exception_zv);
129+
}
117130
}
118131

119132
static PHP_METHOD(V8TryCatch, GetIsolate)
@@ -203,6 +216,18 @@ static PHP_METHOD(V8TryCatch, HasTerminated)
203216
}
204217

205218

219+
static PHP_METHOD(V8TryCatch, getExternalException)
220+
{
221+
zval rv;
222+
223+
if (zend_parse_parameters_none() == FAILURE) {
224+
return;
225+
}
226+
227+
RETVAL_ZVAL(zend_read_property(this_ce, getThis(), ZEND_STRL("external_exception"), 0, &rv), 1, 0);
228+
}
229+
230+
206231
ZEND_BEGIN_ARG_INFO_EX(arginfo_v8_try_catch___construct, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 2)
207232
ZEND_ARG_OBJ_INFO(0, isolate, V8\\Isolate, 0)
208233
ZEND_ARG_OBJ_INFO(0, context, V8\\Context, 0)
@@ -211,6 +236,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_v8_try_catch___construct, ZEND_SEND_BY_VAL, ZEND_
211236
ZEND_ARG_OBJ_INFO(0, message, V8\\Message, 1)
212237
ZEND_ARG_TYPE_INFO(0, can_continue, _IS_BOOL, 0)
213238
ZEND_ARG_TYPE_INFO(0, has_terminated, _IS_BOOL, 0)
239+
ZEND_ARG_OBJ_INFO(0, external_exception, Throwable, 1)
214240
ZEND_END_ARG_INFO()
215241

216242
PHP_V8_ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_v8_try_catch_GetIsolate, ZEND_RETURN_VALUE, 0, V8\\Isolate, 0)
@@ -234,6 +260,9 @@ ZEND_END_ARG_INFO()
234260
PHP_V8_ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_v8_try_catch_HasTerminated, ZEND_RETURN_VALUE, 0, _IS_BOOL, 0)
235261
ZEND_END_ARG_INFO()
236262

263+
PHP_V8_ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_v8_try_catch_getExternalException, ZEND_RETURN_VALUE, 0, Throwable, 1)
264+
ZEND_END_ARG_INFO()
265+
237266

238267
static const zend_function_entry php_v8_try_catch_methods[] = {
239268
PHP_ME(V8TryCatch, __construct, arginfo_v8_try_catch___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
@@ -248,6 +277,8 @@ static const zend_function_entry php_v8_try_catch_methods[] = {
248277
PHP_ME(V8TryCatch, CanContinue, arginfo_v8_try_catch_CanContinue, ZEND_ACC_PUBLIC)
249278
PHP_ME(V8TryCatch, HasTerminated, arginfo_v8_try_catch_HasTerminated, ZEND_ACC_PUBLIC)
250279

280+
PHP_ME(V8TryCatch, getExternalException, arginfo_v8_try_catch_getExternalException, ZEND_ACC_PUBLIC)
281+
251282
PHP_FE_END
252283
};
253284

@@ -266,5 +297,7 @@ PHP_MINIT_FUNCTION (php_v8_try_catch) {
266297
zend_declare_property_null(this_ce, ZEND_STRL("can_continue"), ZEND_ACC_PRIVATE);
267298
zend_declare_property_null(this_ce, ZEND_STRL("has_terminated"), ZEND_ACC_PRIVATE);
268299

300+
zend_declare_property_null(this_ce, ZEND_STRL("external_exception"), ZEND_ACC_PRIVATE);
301+
269302
return SUCCESS;
270303
}

src/php_v8_value.cc

+15
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,16 @@ static HashTable * php_v8_value_gc(zval *object, zval **table, int *n) {
9191

9292
php_v8_callbacks_gc(php_v8_value->persistent_data, &php_v8_value->gc_data, &php_v8_value->gc_data_count, table, n);
9393

94+
if(!Z_ISUNDEF(php_v8_value->exception)) {
95+
*n = *n + 1;
96+
97+
if (php_v8_value->gc_data_count < *n) {
98+
php_v8_value->gc_data = (zval *)safe_erealloc(php_v8_value->gc_data, *n, sizeof(zval), 0);
99+
}
100+
101+
ZVAL_COPY_VALUE(&php_v8_value->gc_data[*n-1], &php_v8_value->exception);
102+
}
103+
94104
return zend_std_get_properties(object);
95105
}
96106

@@ -114,6 +124,11 @@ static void php_v8_value_free(zend_object *object) {
114124
}
115125
}
116126

127+
if (!Z_ISUNDEF(php_v8_value->exception)) {
128+
zval_ptr_dtor(&php_v8_value->exception);
129+
ZVAL_UNDEF(&php_v8_value->exception);
130+
}
131+
117132
if (php_v8_value->gc_data) {
118133
efree(php_v8_value->gc_data);
119134
}

src/php_v8_value.h

+1
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ struct _php_v8_value_t {
111111
bool is_weak;
112112
v8::Persistent<v8::Value> *persistent;
113113
phpv8::PersistentData *persistent_data;
114+
zval exception;
114115

115116
zval *gc_data;
116117
int gc_data_count;

stubs/src/Exception.php

+10-10
Original file line numberDiff line numberDiff line change
@@ -26,49 +26,49 @@ class Exception
2626
* @param Context $context
2727
* @param \V8\StringValue $message
2828
*
29-
* @return Value
29+
* @return \V8\ObjectValue
3030
*/
31-
public static function RangeError(Context $context, StringValue $message): Value
31+
public static function RangeError(Context $context, StringValue $message): ObjectValue
3232
{
3333
}
3434

3535
/**
3636
* @param Context $context
3737
* @param \V8\StringValue $message
3838
*
39-
* @return Value
39+
* @return \V8\ObjectValue
4040
*/
41-
public static function ReferenceError(Context $context, StringValue $message): Value
41+
public static function ReferenceError(Context $context, StringValue $message): ObjectValue
4242
{
4343
}
4444

4545
/**
4646
* @param Context $context
4747
* @param \V8\StringValue $message
4848
*
49-
* @return Value
49+
* @return \V8\ObjectValue
5050
*/
51-
public static function SyntaxError(Context $context, StringValue $message): Value
51+
public static function SyntaxError(Context $context, StringValue $message): ObjectValue
5252
{
5353
}
5454

5555
/**
5656
* @param Context $context
5757
* @param \V8\StringValue $message
5858
*
59-
* @return Value
59+
* @return \V8\ObjectValue
6060
*/
61-
public static function TypeError(Context $context, StringValue $message): Value
61+
public static function TypeError(Context $context, StringValue $message): ObjectValue
6262
{
6363
}
6464

6565
/**
6666
* @param Context $context
6767
* @param \V8\StringValue $message
6868
*
69-
* @return Value | ObjectValue
69+
* @return ObjectValue
7070
*/
71-
public static function Error(Context $context, StringValue $message): Value
71+
public static function Error(Context $context, StringValue $message): ObjectValue
7272
{
7373
}
7474

stubs/src/Isolate.php

+13-17
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
namespace V8;
1616

1717

18+
use Throwable;
19+
use V8\Exceptions\ValueException;
20+
21+
1822
class Isolate
1923
{
2024
public function __construct(StartupData $snapshot = null)
@@ -79,11 +83,17 @@ public function GetEnteredContext(): Context
7983
* has been handled does it become legal to invoke JavaScript operations.
8084
*
8185
* @param Context $context
82-
* @param Value $value
86+
* @param Value $value
87+
* @param Throwable|null $e Exception to associate with a given value.
88+
* Because how underlying object wiring done, wiring PHP to V8 exceptions
89+
* is possible only for V8 exception that are instances of ObjectValue.
8390
*
8491
* @return void
92+
*
93+
* @throws ValueException When trying to associate external exception with non-object value
94+
* @throws ValueException When another external exception is already associated with a given value
8595
*/
86-
public function ThrowException(Context $context, Value $value)
96+
public function ThrowException(Context $context, Value $value, Throwable $e = null)
8797
{
8898
}
8999

@@ -130,20 +140,6 @@ public function CancelTerminateExecution()
130140
{
131141
}
132142

133-
// /**
134-
// * Request V8 to interrupt long running JavaScript code and invoke
135-
// * the given |callback| passing the given |data| to it. After |callback|
136-
// * returns control will be returned to the JavaScript code.
137-
// * There may be a number of interrupt requests in flight.
138-
// * Can be called from another thread without acquiring a |Locker|.
139-
// * Registered |callback| must not reenter interrupted Isolate.
140-
// */
141-
//// void RequestInterrupt(InterruptCallback callback, void* data);
142-
// public function RequestInterrupt()
143-
// {
144-
//
145-
// }
146-
147143
/**
148144
* Optional notification that the embedder is idle.
149145
* V8 uses the notification to perform garbage collection.
@@ -199,7 +195,7 @@ public function IsInUse(): bool
199195
* and report it to the message listeners. The option is off by default.
200196
*
201197
* @param bool $capture
202-
* @param int $frame_limit
198+
* @param int $frame_limit
203199
*/
204200
public function SetCaptureStackTraceForUncaughtExceptions(bool $capture, int $frame_limit = 10)
205201
{

0 commit comments

Comments
 (0)