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

Commit fa7840f

Browse files
committed
Add typed array args unpacking for V8\StringValue and V8\ObjectValue
1 parent 8ad5985 commit fa7840f

File tree

3 files changed

+197
-10
lines changed

3 files changed

+197
-10
lines changed

src/php_v8_function.cc

Lines changed: 191 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ v8::Local<v8::Function> php_v8_value_get_function_local(v8::Isolate *isolate, ph
2929
return v8::Local<v8::Function>::Cast(php_v8_value_get_value_local(isolate, php_v8_value));
3030
};
3131

32-
bool php_v8_function_unpack_args(zval* arguments_zv, zval *this_ptr, int arg_position, v8::Isolate *isolate, int *argc, v8::Local<v8::Value> **argv) {
32+
bool php_v8_function_unpack_args(zval *arguments_zv, int arg_position, v8::Isolate *isolate, int *argc, v8::Local<v8::Value> **argv) {
3333
if (NULL == arguments_zv || zend_hash_num_elements(Z_ARRVAL_P(arguments_zv)) < 1) {
3434
return true;
3535
}
@@ -49,11 +49,17 @@ bool php_v8_function_unpack_args(zval* arguments_zv, zval *this_ptr, int arg_pos
4949

5050
char *exception_message;
5151

52+
#if PHP_VERSION_ID >= 70100
53+
zend_string *ce_name = zend_get_executed_scope()->name;
54+
#else
55+
zend_string *ce_name = EG(scope)->name;
56+
#endif
57+
5258
ZEND_HASH_FOREACH_VAL(myht, pzval) {
5359
if (Z_TYPE_P(pzval) != IS_OBJECT) {
5460
zend_throw_error(zend_ce_type_error,
5561
"Argument %d passed to %s::%s() should be array of \\V8\\Value objects, %s given at %d offset",
56-
arg_position, ZSTR_VAL(Z_OBJCE_P(this_ptr)->name), get_active_function_name(),
62+
arg_position, ZSTR_VAL(ce_name), get_active_function_name(),
5763
zend_zval_type_name(pzval), i);
5864

5965
has_error = true;
@@ -63,7 +69,7 @@ bool php_v8_function_unpack_args(zval* arguments_zv, zval *this_ptr, int arg_pos
6369
if (!instanceof_function(Z_OBJCE_P(pzval), php_v8_value_class_entry)) {
6470
zend_throw_error(zend_ce_type_error,
6571
"Argument %d passed to %s::%s() should be array of \\V8\\Value objects, instance of %s given at %d offset",
66-
arg_position, ZSTR_VAL(Z_OBJCE_P(this_ptr)->name), get_active_function_name(),
72+
arg_position, ZSTR_VAL(ce_name), get_active_function_name(),
6773
ZSTR_VAL(Z_OBJCE_P(pzval)->name), i);
6874

6975
has_error = true;
@@ -77,7 +83,7 @@ bool php_v8_function_unpack_args(zval* arguments_zv, zval *this_ptr, int arg_pos
7783
// less confusing exception message
7884
if (NULL == php_v8_tmp_data->persistent || php_v8_tmp_data->persistent->IsEmpty()) {
7985
spprintf(&exception_message, 0, PHP_V8_EMPTY_VALUE_MSG ": argument %d passed to %s::%s() at %d offset",
80-
arg_position, ZSTR_VAL(Z_OBJCE_P(this_ptr)->name), get_active_function_name(), i);
86+
arg_position, ZSTR_VAL(ce_name), get_active_function_name(), i);
8187

8288
PHP_V8_THROW_EXCEPTION(exception_message);
8389

@@ -89,7 +95,7 @@ bool php_v8_function_unpack_args(zval* arguments_zv, zval *this_ptr, int arg_pos
8995
if (NULL == php_v8_tmp_data->php_v8_isolate || isolate != php_v8_tmp_data->php_v8_isolate->isolate) {
9096
spprintf(&exception_message, 0,
9197
PHP_V8_ISOLATES_MISMATCH_MSG ": argument %d passed to %s::%s() at %d offset",
92-
arg_position, ZSTR_VAL(Z_OBJCE_P(this_ptr)->name), get_active_function_name(), i);
98+
arg_position, ZSTR_VAL(ce_name), get_active_function_name(), i);
9399

94100
PHP_V8_THROW_EXCEPTION(exception_message);
95101

@@ -112,6 +118,184 @@ bool php_v8_function_unpack_args(zval* arguments_zv, zval *this_ptr, int arg_pos
112118
return true;
113119
}
114120

121+
bool php_v8_function_unpack_string_args(zval* arguments_zv, int arg_position, v8::Isolate *isolate, int *argc, v8::Local<v8::String> **argv) {
122+
if (NULL == arguments_zv || zend_hash_num_elements(Z_ARRVAL_P(arguments_zv)) < 1) {
123+
return true;
124+
}
125+
126+
php_v8_value_t *php_v8_tmp_data;
127+
128+
int i = 0;
129+
bool has_error = false;
130+
131+
HashTable *myht;
132+
zval *pzval;
133+
134+
*argc = zend_hash_num_elements(Z_ARRVAL_P(arguments_zv));
135+
*argv = (v8::Local<v8::String> *) ecalloc(static_cast<size_t>(*argc), sizeof(*argv));
136+
137+
myht = Z_ARRVAL_P(arguments_zv);
138+
139+
char *exception_message;
140+
141+
#if PHP_VERSION_ID >= 70100
142+
zend_string *ce_name = zend_get_executed_scope()->name;
143+
#else
144+
zend_string *ce_name = EG(scope)->name;
145+
#endif
146+
147+
ZEND_HASH_FOREACH_VAL(myht, pzval) {
148+
if (Z_TYPE_P(pzval) != IS_OBJECT) {
149+
zend_throw_error(zend_ce_type_error,
150+
"Argument %d passed to %s::%s() should be array of \\V8\\StringValue objects, %s given at %d offset",
151+
arg_position, ZSTR_VAL(ce_name), get_active_function_name(),
152+
zend_zval_type_name(pzval), i);
153+
154+
has_error = true;
155+
break;
156+
}
157+
158+
if (!instanceof_function(Z_OBJCE_P(pzval), php_v8_string_class_entry)) {
159+
zend_throw_error(zend_ce_type_error,
160+
"Argument %d passed to %s::%s() should be array of \\V8\\StringValue, instance of %s given at %d offset",
161+
arg_position, ZSTR_VAL(ce_name), get_active_function_name(),
162+
ZSTR_VAL(Z_OBJCE_P(pzval)->name), i);
163+
164+
has_error = true;
165+
break;
166+
}
167+
168+
php_v8_tmp_data = PHP_V8_VALUE_FETCH(pzval);
169+
170+
// NOTE: check for emptiness may be considered redundant while we may catch the fact that value was not properly
171+
// constructed by checking isolates mismatch, but this check serves for user-friendly purposes to throw
172+
// less confusing exception message
173+
if (NULL == php_v8_tmp_data->persistent || php_v8_tmp_data->persistent->IsEmpty()) {
174+
spprintf(&exception_message, 0, PHP_V8_EMPTY_VALUE_MSG ": argument %d passed to %s::%s() at %d offset",
175+
arg_position, ZSTR_VAL(ce_name), get_active_function_name(), i);
176+
177+
PHP_V8_THROW_EXCEPTION(exception_message);
178+
179+
efree(exception_message);
180+
has_error = true;
181+
break;
182+
}
183+
184+
if (NULL == php_v8_tmp_data->php_v8_isolate || isolate != php_v8_tmp_data->php_v8_isolate->isolate) {
185+
spprintf(&exception_message, 0,
186+
PHP_V8_ISOLATES_MISMATCH_MSG ": argument %d passed to %s::%s() at %d offset",
187+
arg_position, ZSTR_VAL(ce_name), get_active_function_name(), i);
188+
189+
PHP_V8_THROW_EXCEPTION(exception_message);
190+
191+
efree(exception_message);
192+
has_error = true;
193+
break;
194+
}
195+
196+
(*argv)[i++] = php_v8_value_get_string_local(isolate, php_v8_tmp_data);
197+
} ZEND_HASH_FOREACH_END();
198+
199+
if (has_error) {
200+
efree(*argv);
201+
*argv = NULL;
202+
*argc = 0;
203+
204+
return false;
205+
}
206+
207+
return true;
208+
}
209+
210+
bool php_v8_function_unpack_object_args(zval* arguments_zv, int arg_position, v8::Isolate *isolate, int *argc, v8::Local<v8::Object> **argv) {
211+
if (NULL == arguments_zv || zend_hash_num_elements(Z_ARRVAL_P(arguments_zv)) < 1) {
212+
return true;
213+
}
214+
215+
php_v8_value_t *php_v8_tmp_data;
216+
217+
int i = 0;
218+
bool has_error = false;
219+
220+
HashTable *myht;
221+
zval *pzval;
222+
223+
*argc = zend_hash_num_elements(Z_ARRVAL_P(arguments_zv));
224+
*argv = (v8::Local<v8::Object> *) ecalloc(static_cast<size_t>(*argc), sizeof(*argv));
225+
226+
myht = Z_ARRVAL_P(arguments_zv);
227+
228+
char *exception_message;
229+
230+
#if PHP_VERSION_ID >= 70100
231+
zend_string *ce_name = zend_get_executed_scope()->name;
232+
#else
233+
zend_string *ce_name = EG(scope)->name;
234+
#endif
235+
236+
ZEND_HASH_FOREACH_VAL(myht, pzval) {
237+
if (Z_TYPE_P(pzval) != IS_OBJECT) {
238+
zend_throw_error(zend_ce_type_error,
239+
"Argument %d passed to %s::%s() should be array of \\V8\\ObjectValue objects, %s given at %d offset",
240+
arg_position, ZSTR_VAL(ce_name), get_active_function_name(),
241+
zend_zval_type_name(pzval), i);
242+
243+
has_error = true;
244+
break;
245+
}
246+
247+
if (!instanceof_function(Z_OBJCE_P(pzval), php_v8_object_class_entry)) {
248+
zend_throw_error(zend_ce_type_error,
249+
"Argument %d passed to %s::%s() should be array of \\V8\\ObjectValue, instance of %s given at %d offset",
250+
arg_position, ZSTR_VAL(ce_name), get_active_function_name(),
251+
ZSTR_VAL(Z_OBJCE_P(pzval)->name), i);
252+
253+
has_error = true;
254+
break;
255+
}
256+
257+
php_v8_tmp_data = PHP_V8_VALUE_FETCH(pzval);
258+
259+
// NOTE: check for emptiness may be considered redundant while we may catch the fact that value was not properly
260+
// constructed by checking isolates mismatch, but this check serves for user-friendly purposes to throw
261+
// less confusing exception message
262+
if (NULL == php_v8_tmp_data->persistent || php_v8_tmp_data->persistent->IsEmpty()) {
263+
spprintf(&exception_message, 0, PHP_V8_EMPTY_VALUE_MSG ": argument %d passed to %s::%s() at %d offset",
264+
arg_position, ZSTR_VAL(ce_name), get_active_function_name(), i);
265+
266+
PHP_V8_THROW_EXCEPTION(exception_message);
267+
268+
efree(exception_message);
269+
has_error = true;
270+
break;
271+
}
272+
273+
if (NULL == php_v8_tmp_data->php_v8_isolate || isolate != php_v8_tmp_data->php_v8_isolate->isolate) {
274+
spprintf(&exception_message, 0,
275+
PHP_V8_ISOLATES_MISMATCH_MSG ": argument %d passed to %s::%s() at %d offset",
276+
arg_position, ZSTR_VAL(ce_name), get_active_function_name(), i);
277+
278+
PHP_V8_THROW_EXCEPTION(exception_message);
279+
280+
efree(exception_message);
281+
has_error = true;
282+
break;
283+
}
284+
285+
(*argv)[i++] = php_v8_value_get_object_local(isolate, php_v8_tmp_data);
286+
} ZEND_HASH_FOREACH_END();
287+
288+
if (has_error) {
289+
efree(*argv);
290+
*argv = NULL;
291+
*argc = 0;
292+
293+
return false;
294+
}
295+
296+
return true;
297+
}
298+
115299

116300
static PHP_METHOD(V8Function, __construct) {
117301
zval rv;
@@ -194,7 +378,7 @@ static PHP_METHOD(V8Function, NewInstance) {
194378
PHP_V8_ENTER_STORED_ISOLATE(php_v8_context);
195379
PHP_V8_ENTER_CONTEXT(php_v8_context);
196380

197-
if (!php_v8_function_unpack_args(arguments_zv, getThis(), 2, isolate, &argc, &argv)) {
381+
if (!php_v8_function_unpack_args(arguments_zv, 2, isolate, &argc, &argv)) {
198382
return;
199383
}
200384

@@ -239,7 +423,7 @@ static PHP_METHOD(V8Function, Call) {
239423
PHP_V8_ENTER_STORED_ISOLATE(php_v8_context);
240424
PHP_V8_ENTER_CONTEXT(php_v8_context);
241425

242-
if (!php_v8_function_unpack_args(arguments_zv, getThis(), 3, isolate, &argc, &argv)) {
426+
if (!php_v8_function_unpack_args(arguments_zv, 3, isolate, &argc, &argv)) {
243427
return;
244428
}
245429

src/php_v8_function.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ extern "C" {
2727
extern zend_class_entry* php_v8_function_class_entry;
2828

2929
extern v8::Local<v8::Function> php_v8_value_get_function_local(v8::Isolate *isolate, php_v8_value_t *php_v8_value);
30-
extern bool php_v8_function_unpack_args(zval* arguments_zv, zval *this_ptr, int arg_position, v8::Isolate *isolate, int *argc, v8::Local<v8::Value> **argv);
30+
extern bool
31+
php_v8_function_unpack_args(zval *arguments_zv, int arg_position, v8::Isolate *isolate, int *argc, v8::Local<v8::Value> **argv);
32+
extern bool php_v8_function_unpack_string_args(zval* arguments_zv, int arg_position, v8::Isolate *isolate, int *argc, v8::Local<v8::String> **argv);
33+
extern bool php_v8_function_unpack_object_args(zval* arguments_zv, int arg_position, v8::Isolate *isolate, int *argc, v8::Local<v8::Object> **argv);
3134

3235
#define PHP_V8_CHECK_FUNCTION_LENGTH_RANGE(val, message) \
3336
if ((val) > INT_MAX || (val) < INT_MIN) { \

src/php_v8_object.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,7 +1196,7 @@ static PHP_METHOD(V8Object, CallAsFunction) {
11961196
PHP_V8_ENTER_STORED_ISOLATE(php_v8_context);
11971197
PHP_V8_ENTER_CONTEXT(php_v8_context);
11981198

1199-
if (!php_v8_function_unpack_args(arguments_zv, getThis(), 3, isolate, &argc, &argv)) {
1199+
if (!php_v8_function_unpack_args(arguments_zv, 3, isolate, &argc, &argv)) {
12001200
return;
12011201
}
12021202

@@ -1239,7 +1239,7 @@ static PHP_METHOD(V8Object, CallAsConstructor) {
12391239
PHP_V8_ENTER_STORED_ISOLATE(php_v8_context);
12401240
PHP_V8_ENTER_CONTEXT(php_v8_context);
12411241

1242-
if (!php_v8_function_unpack_args(arguments_zv, getThis(), 2, isolate, &argc, &argv)) {
1242+
if (!php_v8_function_unpack_args(arguments_zv, 2, isolate, &argc, &argv)) {
12431243
return;
12441244
}
12451245

0 commit comments

Comments
 (0)