Skip to content

Commit 21ed0f8

Browse files
authored
Merge pull request #510 from chrisbckr/php8-tojson
Implements toJSON function that redirects to jsonSerialize
2 parents 752cfa1 + f696867 commit 21ed0f8

File tree

2 files changed

+48
-0
lines changed

2 files changed

+48
-0
lines changed

tests/tojson_001.phpt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
--TEST--
2+
Test V8::executeString() : redirects toJSON() to jsonSerialize
3+
--SKIPIF--
4+
<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?>
5+
--FILE--
6+
<?php
7+
class Foo implements JsonSerializable {
8+
public function jsonSerialize(): mixed {
9+
return ['foo', 'bar'];
10+
}
11+
}
12+
13+
$v8 = new V8Js;
14+
$v8->foo = new Foo;
15+
$v8->executeString('var_dump(JSON.stringify(PHP.foo));');
16+
?>
17+
===EOF===
18+
--EXPECTF--
19+
string(13) "["foo","bar"]"
20+
===EOF===

v8js_object_export.cc

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,6 +1007,34 @@ static v8::MaybeLocal<v8::Object> v8js_wrap_object(v8::Isolate *isolate, zend_cl
10071007

10081008
v8::MaybeLocal<v8::Object> newobj = constr->NewInstance(v8_context, 1, &external);
10091009

1010+
bool has_json_serializable = false;
1011+
for (unsigned int i = 0; i < ce->num_interfaces; i ++) {
1012+
if (strcmp (ZSTR_VAL(ce->interfaces[i]->name), "JsonSerializable") == 0) {
1013+
has_json_serializable = true;
1014+
break;
1015+
}
1016+
}
1017+
1018+
if (has_json_serializable) {
1019+
zend_string *jsonserialize_str = zend_string_init
1020+
("jsonSerialize", sizeof("jsonSerialize") - 1, 0);
1021+
zend_function *jsonserialize_method_ptr = reinterpret_cast<zend_function *>
1022+
(zend_hash_find_ptr_lc(&ce->function_table, jsonserialize_str));
1023+
if (jsonserialize_method_ptr &&
1024+
jsonserialize_method_ptr->common.fn_flags & ZEND_ACC_PUBLIC) {
1025+
v8::Local<v8::String> method_name = V8JS_SYM("toJSON");
1026+
v8::Local<v8::FunctionTemplate> ft;
1027+
1028+
ft = v8::FunctionTemplate::New(isolate, v8js_php_callback,
1029+
v8::External::New((isolate), jsonserialize_method_ptr));
1030+
1031+
v8js_function_tmpl_t *persistent_ft = &ctx->method_tmpls[std::make_pair(ce, jsonserialize_method_ptr)];
1032+
persistent_ft->Reset(isolate, ft);
1033+
1034+
newobj.ToLocalChecked()->CreateDataProperty(v8_context, method_name, ft->GetFunction(v8_context).ToLocalChecked());
1035+
}
1036+
}
1037+
10101038
if (ce == zend_ce_closure && !newobj.IsEmpty()) {
10111039
// free uncached function template when object is freed
10121040
ctx->weak_closures[persist_tpl_].Reset(isolate, newobj.ToLocalChecked());

0 commit comments

Comments
 (0)