From d246ddd3a8cdf0fb494e8d10fbe80d035e944f77 Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Sat, 27 Nov 2021 08:59:31 -0500 Subject: [PATCH] Allow dynamic properties (e.g. endLineno) without deprecation notice in ast\Node (But use the default deprecation behavior for ast\Metadata) 1. php-ast itself sets the dynamic property on endLineno right now, causing deprecation notices in PHP 8.2. Because all declaration types are associative arrays(not lists), a future AST version number may add this as a property of $node->children instead to avoid this notice. 2. WeakMap is only available in PHP 8.0+ (and WeakReference 7.4), but https://github.com/phan/phan targets PHP 7.2+. 3. Because some nodes make `$node->children` a list, applications such as Phan using php-ast can't associate string keys with that. (e.g. to mark nodes that were already processed in a certain step) https://github.com/nikic/php-parser solves that by adding `attributes`, `setAttribute`, `getAttribute`, etc. separately from children, but php-ast currently doesn't have an attributes node. That may be worth it in a future release. 4. When processing a large number of ast nodes in a large number of files, the deprecation notices have a noticeable performance impact, even when suppressed. Related to #214 --- ast.c | 8 +++++++ package.xml | 3 ++- tests/php82_metadata.phpt | 48 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 tests/php82_metadata.phpt diff --git a/ast.c b/ast.c index cd4d54d..6c2a653 100644 --- a/ast.c +++ b/ast.c @@ -13,6 +13,10 @@ #include "zend_language_parser.h" #include "zend_exceptions.h" #include "zend_smart_str.h" +#if PHP_VERSION_ID >= 80200 +/* Used for AllowDynamicProperties */ +#include "zend_attributes.h" +#endif #ifndef ZEND_ARG_INFO_WITH_DEFAULT_VALUE #define ZEND_ARG_INFO_WITH_DEFAULT_VALUE(pass_by_ref, name, default_value) \ @@ -1518,6 +1522,10 @@ PHP_MINIT_FUNCTION(ast) { ast_declare_property(ast_node_ce, AST_STR(str_flags), &zv_null); ast_declare_property(ast_node_ce, AST_STR(str_lineno), &zv_null); ast_declare_property(ast_node_ce, AST_STR(str_children), &zv_null); +#ifdef ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES + zend_add_class_attribute(ast_node_ce, zend_ce_allow_dynamic_properties->name, 0); + ast_node_ce->ce_flags |= ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES; +#endif INIT_CLASS_ENTRY(tmp_ce, "ast\\Metadata", NULL); ast_metadata_ce = zend_register_internal_class(&tmp_ce); diff --git a/package.xml b/package.xml index a7d4d0f..9193e1f 100644 --- a/package.xml +++ b/package.xml @@ -29,7 +29,7 @@ BSD-3-Clause -- TBD +- Allow ast\Node to have dynamic properties without emitting a notice in PHP 8.2. @@ -115,6 +115,7 @@ + diff --git a/tests/php82_metadata.phpt b/tests/php82_metadata.phpt new file mode 100644 index 0000000..bd643e2 --- /dev/null +++ b/tests/php82_metadata.phpt @@ -0,0 +1,48 @@ +--TEST-- +Dynamic property support in php 8.2+ +--SKIPIF-- +=8.2 only'); ?> +--FILE-- +getAttributes() as $attribute) { + echo "- " . $attribute->getName() . "\n"; + } +} + +$node = new ast\Node(); +$node->undeclaredDynamic = 123; +dump($node); +$metadata = new ast\Metadata(); +$metadata->undeclaredDynamic = 123; +dump($metadata); +dump_attributes(ast\Node::class); +dump_attributes(ast\Metadata::class); +--EXPECTF-- +ast\Node::__set_state(array( + 'kind' => NULL, + 'flags' => NULL, + 'lineno' => NULL, + 'children' => NULL, + 'undeclaredDynamic' => 123, +)) +Deprecated: Creation of dynamic property ast\Metadata::$undeclaredDynamic is deprecated in %sphp82_metadata.php on line 21 +ast\Metadata::__set_state(array( + 'kind' => NULL, + 'name' => NULL, + 'flags' => NULL, + 'flagsCombinable' => NULL, + 'undeclaredDynamic' => 123, +)) +Attributes of ast\Node: +- AllowDynamicProperties +Attributes of ast\Metadata: