From 3d94aa18a4ddfadefeb9ffc3686e3d805a13371e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Fri, 6 May 2022 09:49:04 +0200 Subject: [PATCH] Declare tidyNode properties as readonly --- ext/tidy/tests/010.phpt | 4 +- ext/tidy/tests/012.phpt | 40 +++++-- ext/tidy/tests/036.phpt | 75 ++++++++++++ ext/tidy/tidy.c | 248 ++++++++++++++++++++++------------------ ext/tidy/tidy.stub.php | 10 ++ ext/tidy/tidy_arginfo.h | 56 ++++++++- 6 files changed, 311 insertions(+), 122 deletions(-) create mode 100644 ext/tidy/tests/036.phpt diff --git a/ext/tidy/tests/010.phpt b/ext/tidy/tests/010.phpt index 338d4047c898b..39d500e320a96 100644 --- a/ext/tidy/tests/010.phpt +++ b/ext/tidy/tests/010.phpt @@ -12,7 +12,7 @@ var_dump($a->head()); ?> --EXPECTF-- -object(tidyNode)#2 (8) { +object(tidyNode)#2 (9) { ["value"]=> string(94) " @@ -31,6 +31,8 @@ object(tidyNode)#2 (8) { int(1) ["proprietary"]=> bool(false) + ["id"]=> + NULL ["attribute"]=> NULL ["child"]=> diff --git a/ext/tidy/tests/012.phpt b/ext/tidy/tests/012.phpt index 0e6cf42ccac1e..1edc50fa7a5db 100644 --- a/ext/tidy/tests/012.phpt +++ b/ext/tidy/tests/012.phpt @@ -148,7 +148,7 @@ object(tidyNode)#5 (9) { ["child"]=> array(1) { [0]=> - object(tidyNode)#7 (8) { + object(tidyNode)#7 (9) { ["value"]=> string(2) "Hi" ["name"]=> @@ -161,6 +161,8 @@ object(tidyNode)#5 (9) { int(46) ["proprietary"]=> bool(false) + ["id"]=> + NULL ["attribute"]=> NULL ["child"]=> @@ -189,7 +191,7 @@ object(tidyNode)#5 (9) { ["child"]=> array(2) { [0]=> - object(tidyNode)#9 (8) { + object(tidyNode)#9 (9) { ["value"]=> string(3) "Bye" ["name"]=> @@ -202,6 +204,8 @@ object(tidyNode)#5 (9) { int(55) ["proprietary"]=> bool(false) + ["id"]=> + NULL ["attribute"]=> NULL ["child"]=> @@ -228,7 +232,7 @@ object(tidyNode)#5 (9) { ["child"]=> array(1) { [0]=> - object(tidyNode)#11 (8) { + object(tidyNode)#11 (9) { ["value"]=> string(4) "Test" ["name"]=> @@ -241,6 +245,8 @@ object(tidyNode)#5 (9) { int(61) ["proprietary"]=> bool(false) + ["id"]=> + NULL ["attribute"]=> NULL ["child"]=> @@ -273,7 +279,7 @@ object(tidyNode)#6 (9) { ["child"]=> array(1) { [0]=> - object(tidyNode)#7 (8) { + object(tidyNode)#7 (9) { ["value"]=> string(2) "Hi" ["name"]=> @@ -286,6 +292,8 @@ object(tidyNode)#6 (9) { int(46) ["proprietary"]=> bool(false) + ["id"]=> + NULL ["attribute"]=> NULL ["child"]=> @@ -294,7 +302,7 @@ object(tidyNode)#6 (9) { } } bool(true) -object(tidyNode)#7 (8) { +object(tidyNode)#7 (9) { ["value"]=> string(2) "Hi" ["name"]=> @@ -307,6 +315,8 @@ object(tidyNode)#7 (8) { int(46) ["proprietary"]=> bool(false) + ["id"]=> + NULL ["attribute"]=> NULL ["child"]=> @@ -332,7 +342,7 @@ object(tidyNode)#8 (9) { ["child"]=> array(2) { [0]=> - object(tidyNode)#9 (8) { + object(tidyNode)#9 (9) { ["value"]=> string(3) "Bye" ["name"]=> @@ -345,6 +355,8 @@ object(tidyNode)#8 (9) { int(55) ["proprietary"]=> bool(false) + ["id"]=> + NULL ["attribute"]=> NULL ["child"]=> @@ -371,7 +383,7 @@ object(tidyNode)#8 (9) { ["child"]=> array(1) { [0]=> - object(tidyNode)#11 (8) { + object(tidyNode)#11 (9) { ["value"]=> string(4) "Test" ["name"]=> @@ -384,6 +396,8 @@ object(tidyNode)#8 (9) { int(61) ["proprietary"]=> bool(false) + ["id"]=> + NULL ["attribute"]=> NULL ["child"]=> @@ -394,7 +408,7 @@ object(tidyNode)#8 (9) { } } bool(true) -object(tidyNode)#9 (8) { +object(tidyNode)#9 (9) { ["value"]=> string(3) "Bye" ["name"]=> @@ -407,6 +421,8 @@ object(tidyNode)#9 (8) { int(55) ["proprietary"]=> bool(false) + ["id"]=> + NULL ["attribute"]=> NULL ["child"]=> @@ -432,7 +448,7 @@ object(tidyNode)#10 (9) { ["child"]=> array(1) { [0]=> - object(tidyNode)#11 (8) { + object(tidyNode)#11 (9) { ["value"]=> string(4) "Test" ["name"]=> @@ -445,6 +461,8 @@ object(tidyNode)#10 (9) { int(61) ["proprietary"]=> bool(false) + ["id"]=> + NULL ["attribute"]=> NULL ["child"]=> @@ -453,7 +471,7 @@ object(tidyNode)#10 (9) { } } bool(true) -object(tidyNode)#11 (8) { +object(tidyNode)#11 (9) { ["value"]=> string(4) "Test" ["name"]=> @@ -466,6 +484,8 @@ object(tidyNode)#11 (8) { int(61) ["proprietary"]=> bool(false) + ["id"]=> + NULL ["attribute"]=> NULL ["child"]=> diff --git a/ext/tidy/tests/036.phpt b/ext/tidy/tests/036.phpt new file mode 100644 index 0000000000000..d328c4862fe78 --- /dev/null +++ b/ext/tidy/tests/036.phpt @@ -0,0 +1,75 @@ +--TEST-- +Test readonly tidyNode properties +--EXTENSIONS-- +tidy +--FILE-- +"); +$node = $tidy->body(); + +try { + $node->value = ""; +} catch (Error $exception) { + echo $exception->getMessage() . "\n"; +} + +try { + $node->name = ""; +} catch (Error $exception) { + echo $exception->getMessage() . "\n"; +} + +try { + $node->type = 1; +} catch (Error $exception) { + echo $exception->getMessage() . "\n"; +} + +try { + $node->line = 1; +} catch (Error $exception) { + echo $exception->getMessage() . "\n"; +} + +try { + $node->column = 1; +} catch (Error $exception) { + echo $exception->getMessage() . "\n"; +} + +try { + $node->proprietary = true; +} catch (Error $exception) { + echo $exception->getMessage() . "\n"; +} + +try { + $node->id = null; +} catch (Error $exception) { + echo $exception->getMessage() . "\n"; +} + +try { + $node->attribute = []; +} catch (Error $exception) { + echo $exception->getMessage() . "\n"; +} + +try { + $node->child = []; +} catch (Error $exception) { + echo $exception->getMessage() . "\n"; +} + +?> +--EXPECT-- +Cannot modify readonly property tidyNode::$value +Cannot modify readonly property tidyNode::$name +Cannot modify readonly property tidyNode::$type +Cannot modify readonly property tidyNode::$line +Cannot modify readonly property tidyNode::$column +Cannot modify readonly property tidyNode::$proprietary +Cannot modify readonly property tidyNode::$id +Cannot modify readonly property tidyNode::$attribute +Cannot modify readonly property tidyNode::$child diff --git a/ext/tidy/tidy.c b/ext/tidy/tidy.c index 342b3039adddc..d83dbdbc93a27 100644 --- a/ext/tidy/tidy.c +++ b/ext/tidy/tidy.c @@ -93,42 +93,6 @@ #define TIDY_TAG_CONST(tag) REGISTER_LONG_CONSTANT("TIDY_TAG_" #tag, TidyTag_##tag, CONST_CS | CONST_PERSISTENT) #define TIDY_NODE_CONST(name, type) REGISTER_LONG_CONSTANT("TIDY_NODETYPE_" #name, TidyNode_##type, CONST_CS | CONST_PERSISTENT) -#define ADD_PROPERTY_STRING(_table, _key, _string) \ - { \ - zval tmp; \ - if (_string) { \ - ZVAL_STRING(&tmp, (char *)_string); \ - } else { \ - ZVAL_EMPTY_STRING(&tmp); \ - } \ - zend_hash_str_update(_table, #_key, sizeof(#_key) - 1, &tmp); \ - } - -#define ADD_PROPERTY_STRINGL(_table, _key, _string, _len) \ - { \ - zval tmp; \ - if (_string) { \ - ZVAL_STRINGL(&tmp, (char *)_string, _len); \ - } else { \ - ZVAL_EMPTY_STRING(&tmp); \ - } \ - zend_hash_str_update(_table, #_key, sizeof(#_key) - 1, &tmp); \ - } - -#define ADD_PROPERTY_LONG(_table, _key, _long) \ - { \ - zval tmp; \ - ZVAL_LONG(&tmp, _long); \ - zend_hash_str_update(_table, #_key, sizeof(#_key) - 1, &tmp); \ - } - -#define ADD_PROPERTY_BOOL(_table, _key, _bool) \ - { \ - zval tmp; \ - ZVAL_BOOL(&tmp, _bool); \ - zend_hash_str_update(_table, #_key, sizeof(#_key) - 1, &tmp); \ - } - #define TIDY_OPEN_BASE_DIR_CHECK(filename) \ if (php_check_open_basedir(filename)) { \ RETURN_FALSE; \ @@ -184,11 +148,11 @@ static zend_string *php_tidy_file_to_mem(char *, bool); static void tidy_object_free_storage(zend_object *); static zend_object *tidy_object_new_node(zend_class_entry *); static zend_object *tidy_object_new_doc(zend_class_entry *); -static zval * tidy_instanciate(zend_class_entry *, zval *); +static zval *tidy_instantiate(zend_class_entry *, zval *); static int tidy_doc_cast_handler(zend_object *, zval *, int); static int tidy_node_cast_handler(zend_object *, zval *, int); static void tidy_doc_update_properties(PHPTidyObj *); -static void tidy_add_default_properties(PHPTidyObj *, tidy_obj_type); +static void tidy_add_node_default_properties(PHPTidyObj *); static void *php_tidy_get_opt_val(PHPTidyDoc *, TidyOption, TidyOptionType *); static void php_tidy_create_node(INTERNAL_FUNCTION_PARAMETERS, tidy_base_nodetypes); static int _php_tidy_set_tidy_opt(TidyDoc, char *, zval *); @@ -474,8 +438,6 @@ static zend_object *tidy_object_new(zend_class_entry *class_type, zend_object_ha tidyOptSetBool(intern->ptdoc->doc, TidyMark, no); TIDY_SET_DEFAULT_CONFIG(intern->ptdoc->doc); - - tidy_add_default_properties(intern, is_doc); break; } @@ -494,7 +456,7 @@ static zend_object *tidy_object_new_doc(zend_class_entry *class_type) return tidy_object_new(class_type, &tidy_object_handlers_doc, is_doc); } -static zval * tidy_instanciate(zend_class_entry *pce, zval *object) +static zval *tidy_instantiate(zend_class_entry *pce, zval *object) { object_init_ex(object, pce); return object; @@ -589,7 +551,7 @@ static void tidy_doc_update_properties(PHPTidyObj *obj) &obj->std, "value", sizeof("value") - 1, - (char*)output.bp, + (char*) output.bp, output.size-1 ); } @@ -602,91 +564,157 @@ static void tidy_doc_update_properties(PHPTidyObj *obj) &obj->std, "errorBuffer", sizeof("errorBuffer") - 1, - (char*)obj->ptdoc->errbuf->bp, + (char*) obj->ptdoc->errbuf->bp, obj->ptdoc->errbuf->size-1 ); } } -static void tidy_add_default_properties(PHPTidyObj *obj, tidy_obj_type type) +static void tidy_add_node_default_properties(PHPTidyObj *obj) { TidyBuffer buf; TidyAttr tempattr; TidyNode tempnode; zval attribute, children, temp; PHPTidyObj *newobj; + char *name; - switch(type) { - - case is_node: - if (!obj->std.properties) { - rebuild_object_properties(&obj->std); - } - tidyBufInit(&buf); - tidyNodeGetText(obj->ptdoc->doc, obj->node, &buf); - ADD_PROPERTY_STRINGL(obj->std.properties, value, buf.bp, buf.size ? buf.size-1 : 0); - tidyBufFree(&buf); + tidyBufInit(&buf); + tidyNodeGetText(obj->ptdoc->doc, obj->node, &buf); + + zend_update_property_stringl( + tidy_ce_node, + &obj->std, + "value", + sizeof("value") - 1, + buf.size ? (char *) buf.bp : "", + buf.size ? buf.size - 1 : 0 + ); + + tidyBufFree(&buf); + + name = (char *) tidyNodeGetName(obj->node); + + zend_update_property_string( + tidy_ce_node, + &obj->std, + "name", + sizeof("name") - 1, + name ? name : "" + ); + + zend_update_property_long( + tidy_ce_node, + &obj->std, + "type", + sizeof("type") - 1, + tidyNodeGetType(obj->node) + ); + + zend_update_property_long( + tidy_ce_node, + &obj->std, + "line", + sizeof("line") - 1, + tidyNodeLine(obj->node) + ); + + zend_update_property_long( + tidy_ce_node, + &obj->std, + "column", + sizeof("column") - 1, + tidyNodeColumn(obj->node) + ); + + zend_update_property_bool( + tidy_ce_node, + &obj->std, + "proprietary", + sizeof("proprietary") - 1, + tidyNodeIsProp(obj->ptdoc->doc, obj->node) + ); + + switch(tidyNodeGetType(obj->node)) { + case TidyNode_Root: + case TidyNode_DocType: + case TidyNode_Text: + case TidyNode_Comment: + zend_update_property_null( + tidy_ce_node, + &obj->std, + "id", + sizeof("id") - 1 + ); + break; - ADD_PROPERTY_STRING(obj->std.properties, name, tidyNodeGetName(obj->node)); - ADD_PROPERTY_LONG(obj->std.properties, type, tidyNodeGetType(obj->node)); - ADD_PROPERTY_LONG(obj->std.properties, line, tidyNodeLine(obj->node)); - ADD_PROPERTY_LONG(obj->std.properties, column, tidyNodeColumn(obj->node)); - ADD_PROPERTY_BOOL(obj->std.properties, proprietary, tidyNodeIsProp(obj->ptdoc->doc, obj->node)); - - switch(tidyNodeGetType(obj->node)) { - case TidyNode_Root: - case TidyNode_DocType: - case TidyNode_Text: - case TidyNode_Comment: - break; - - default: - ADD_PROPERTY_LONG(obj->std.properties, id, tidyNodeGetId(obj->node)); + default: + zend_update_property_long( + tidy_ce_node, + &obj->std, + "id", + sizeof("id") - 1, + tidyNodeGetId(obj->node) + ); + } + + tempattr = tidyAttrFirst(obj->node); + + if (tempattr) { + char *name, *val; + array_init(&attribute); + + do { + name = (char *)tidyAttrName(tempattr); + val = (char *)tidyAttrValue(tempattr); + if (name && val) { + add_assoc_string(&attribute, name, val); } + } while((tempattr = tidyAttrNext(tempattr))); + } else { + ZVAL_NULL(&attribute); + } - tempattr = tidyAttrFirst(obj->node); + zend_update_property( + tidy_ce_node, + &obj->std, + "attribute", + sizeof("attribute") - 1, + &attribute + ); - if (tempattr) { - char *name, *val; - array_init(&attribute); + zval_ptr_dtor(&attribute); - do { - name = (char *)tidyAttrName(tempattr); - val = (char *)tidyAttrValue(tempattr); - if (name && val) { - add_assoc_string(&attribute, name, val); - } - } while((tempattr = tidyAttrNext(tempattr))); - } else { - ZVAL_NULL(&attribute); - } - zend_hash_str_update(obj->std.properties, "attribute", sizeof("attribute") - 1, &attribute); + tempnode = tidyGetChild(obj->node); - tempnode = tidyGetChild(obj->node); + if (tempnode) { + array_init(&children); + do { + tidy_instantiate(tidy_ce_node, &temp); + newobj = Z_TIDY_P(&temp); + newobj->node = tempnode; + newobj->type = is_node; + newobj->ptdoc = obj->ptdoc; + newobj->ptdoc->ref_count++; - if (tempnode) { - array_init(&children); - do { - tidy_instanciate(tidy_ce_node, &temp); - newobj = Z_TIDY_P(&temp); - newobj->node = tempnode; - newobj->type = is_node; - newobj->ptdoc = obj->ptdoc; - newobj->ptdoc->ref_count++; + tidy_add_node_default_properties(newobj); + add_next_index_zval(&children, &temp); - tidy_add_default_properties(newobj, is_node); - add_next_index_zval(&children, &temp); + } while((tempnode = tidyGetNext(tempnode))); - } while((tempnode = tidyGetNext(tempnode))); - - } else { - ZVAL_NULL(&children); - } + } else { + ZVAL_NULL(&children); + } - zend_hash_str_update(obj->std.properties, "child", sizeof("child") - 1, &children); + zend_update_property( + tidy_ce_node, + &obj->std, + "child", + sizeof("child") - 1, + &children + ); - break; - } + zval_ptr_dtor(&children); } static void *php_tidy_get_opt_val(PHPTidyDoc *ptdoc, TidyOption opt, TidyOptionType *type) @@ -747,14 +775,14 @@ static void php_tidy_create_node(INTERNAL_FUNCTION_PARAMETERS, tidy_base_nodetyp RETURN_NULL(); } - tidy_instanciate(tidy_ce_node, return_value); + tidy_instantiate(tidy_ce_node, return_value); newobj = Z_TIDY_P(return_value); newobj->type = is_node; newobj->ptdoc = obj->ptdoc; newobj->node = node; newobj->ptdoc->ref_count++; - tidy_add_default_properties(newobj, is_node); + tidy_add_node_default_properties(newobj); } static int _php_tidy_apply_config_array(TidyDoc doc, HashTable *ht_options) @@ -990,7 +1018,7 @@ PHP_FUNCTION(tidy_parse_string) RETURN_THROWS(); } - tidy_instanciate(tidy_ce_doc, return_value); + tidy_instantiate(tidy_ce_doc, return_value); obj = Z_TIDY_P(return_value); TIDY_APPLY_CONFIG(obj->ptdoc->doc, options_str, options_ht); @@ -1048,7 +1076,7 @@ PHP_FUNCTION(tidy_parse_file) Z_PARAM_BOOL(use_include_path) ZEND_PARSE_PARAMETERS_END(); - tidy_instanciate(tidy_ce_doc, return_value); + tidy_instantiate(tidy_ce_doc, return_value); obj = Z_TIDY_P(return_value); if (!(contents = php_tidy_file_to_mem(ZSTR_VAL(inputfile), use_include_path))) { @@ -1581,13 +1609,13 @@ PHP_METHOD(tidyNode, getParent) parent_node = tidyGetParent(obj->node); if(parent_node) { - tidy_instanciate(tidy_ce_node, return_value); + tidy_instantiate(tidy_ce_node, return_value); newobj = Z_TIDY_P(return_value); newobj->node = parent_node; newobj->type = is_node; newobj->ptdoc = obj->ptdoc; newobj->ptdoc->ref_count++; - tidy_add_default_properties(newobj, is_node); + tidy_add_node_default_properties(newobj); } else { ZVAL_NULL(return_value); } diff --git a/ext/tidy/tidy.stub.php b/ext/tidy/tidy.stub.php index d159834cb8a33..8890522238d86 100644 --- a/ext/tidy/tidy.stub.php +++ b/ext/tidy/tidy.stub.php @@ -166,6 +166,16 @@ public function body(): ?tidyNode {} final class tidyNode { + public readonly string $value; + public readonly string $name; + public readonly int $type; + public readonly int $line; + public readonly int $column; + public readonly bool $proprietary; + public readonly ?int $id; + public readonly ?array $attribute; + public readonly ?array $child; + private function __construct() {} public function hasChildren(): bool {} diff --git a/ext/tidy/tidy_arginfo.h b/ext/tidy/tidy_arginfo.h index bc97305efa6f1..72fc6cd566eb1 100644 --- a/ext/tidy/tidy_arginfo.h +++ b/ext/tidy/tidy_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 7ec9389d5540e60e5bffeeca866168f0a6d6835c */ + * Stub hash: 88c2a02073fc4cebabb4ace0d8db25f9bb017209 */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_tidy_parse_string, 0, 1, tidy, MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, string, IS_STRING, 0) @@ -326,5 +326,59 @@ static zend_class_entry *register_class_tidyNode(void) class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL; + zval property_value_default_value; + ZVAL_UNDEF(&property_value_default_value); + zend_string *property_value_name = zend_string_init("value", sizeof("value") - 1, 1); + zend_declare_typed_property(class_entry, property_value_name, &property_value_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); + zend_string_release(property_value_name); + + zval property_name_default_value; + ZVAL_UNDEF(&property_name_default_value); + zend_string *property_name_name = zend_string_init("name", sizeof("name") - 1, 1); + zend_declare_typed_property(class_entry, property_name_name, &property_name_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); + zend_string_release(property_name_name); + + zval property_type_default_value; + ZVAL_UNDEF(&property_type_default_value); + zend_string *property_type_name = zend_string_init("type", sizeof("type") - 1, 1); + zend_declare_typed_property(class_entry, property_type_name, &property_type_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(property_type_name); + + zval property_line_default_value; + ZVAL_UNDEF(&property_line_default_value); + zend_string *property_line_name = zend_string_init("line", sizeof("line") - 1, 1); + zend_declare_typed_property(class_entry, property_line_name, &property_line_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(property_line_name); + + zval property_column_default_value; + ZVAL_UNDEF(&property_column_default_value); + zend_string *property_column_name = zend_string_init("column", sizeof("column") - 1, 1); + zend_declare_typed_property(class_entry, property_column_name, &property_column_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(property_column_name); + + zval property_proprietary_default_value; + ZVAL_UNDEF(&property_proprietary_default_value); + zend_string *property_proprietary_name = zend_string_init("proprietary", sizeof("proprietary") - 1, 1); + zend_declare_typed_property(class_entry, property_proprietary_name, &property_proprietary_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL)); + zend_string_release(property_proprietary_name); + + zval property_id_default_value; + ZVAL_UNDEF(&property_id_default_value); + zend_string *property_id_name = zend_string_init("id", sizeof("id") - 1, 1); + zend_declare_typed_property(class_entry, property_id_name, &property_id_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG|MAY_BE_NULL)); + zend_string_release(property_id_name); + + zval property_attribute_default_value; + ZVAL_UNDEF(&property_attribute_default_value); + zend_string *property_attribute_name = zend_string_init("attribute", sizeof("attribute") - 1, 1); + zend_declare_typed_property(class_entry, property_attribute_name, &property_attribute_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY|MAY_BE_NULL)); + zend_string_release(property_attribute_name); + + zval property_child_default_value; + ZVAL_UNDEF(&property_child_default_value); + zend_string *property_child_name = zend_string_init("child", sizeof("child") - 1, 1); + zend_declare_typed_property(class_entry, property_child_name, &property_child_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY|MAY_BE_NULL)); + zend_string_release(property_child_name); + return class_entry; }