diff --git a/NEWS b/NEWS index eea553c105135..8b8000311cdeb 100644 --- a/NEWS +++ b/NEWS @@ -25,6 +25,10 @@ PHP NEWS . Invalid values now throw in Phar::mungServer() instead of being silently ignored. (nielsdos) +- Reflection: + . Fixed bug GH-20217 (ReflectionClass::isIterable() incorrectly returns true + for classes with property hooks). (alexandre-daubois) + - Standard: . Fixed bug GH-19926 (reset internal pointer earlier while splicing array while COW violation flag is still set). (alexandre-daubois) diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index a0c1b9f812430..a86ce16feb407 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -5589,7 +5589,8 @@ ZEND_METHOD(ReflectionClass, isIterable) RETURN_FALSE; } - RETURN_BOOL(ce->get_iterator || instanceof_function(ce, zend_ce_traversable)); + RETURN_BOOL((ce->get_iterator && ce->get_iterator != zend_hooked_object_get_iterator) + || instanceof_function(ce, zend_ce_traversable)); } /* }}} */ diff --git a/ext/reflection/tests/ReflectionClass_isIterable_gh20217.phpt b/ext/reflection/tests/ReflectionClass_isIterable_gh20217.phpt new file mode 100644 index 0000000000000..f64fc1efcd414 --- /dev/null +++ b/ext/reflection/tests/ReflectionClass_isIterable_gh20217.phpt @@ -0,0 +1,38 @@ +--TEST-- +GH-20217 (ReflectionClass::isIterable() should return false for classes with property hooks) +--FILE-- + 'virtual'; + } +} + +class IterableClassWithPropertyHooks implements IteratorAggregate +{ + public string $name { + get => 'virtual'; + } + + public function getIterator(): Traversable + { + return new ArrayIterator([]); + } +} + +$classes = [ + 'ClassWithPropertyHooks' => false, + 'IterableClassWithPropertyHooks' => true, +]; + +foreach ($classes as $className => $expected) { + $status = (new ReflectionClass($className)->isIterable() === $expected) ? 'PASS' : 'FAIL'; + echo "$className: $status\n"; +} + +?> +--EXPECT-- +ClassWithPropertyHooks: PASS +IterableClassWithPropertyHooks: PASS diff --git a/ext/uri/uri_parser_rfc3986.c b/ext/uri/uri_parser_rfc3986.c index 30707fde13020..a24fb467bf340 100644 --- a/ext/uri/uri_parser_rfc3986.c +++ b/ext/uri/uri_parser_rfc3986.c @@ -149,7 +149,7 @@ static zend_result php_uri_parser_rfc3986_scheme_write(void *uri, zval *value, z } } -ZEND_ATTRIBUTE_NONNULL zend_result php_uri_parser_rfc3986_userinfo_read(void *uri, php_uri_component_read_mode read_mode, zval *retval) +ZEND_ATTRIBUTE_NONNULL zend_result php_uri_parser_rfc3986_userinfo_read(php_uri_parser_rfc3986_uris *uri, php_uri_component_read_mode read_mode, zval *retval) { const UriUriA *uriparser_uri = get_uri_for_reading(uri, read_mode); @@ -162,7 +162,7 @@ ZEND_ATTRIBUTE_NONNULL zend_result php_uri_parser_rfc3986_userinfo_read(void *ur return SUCCESS; } -zend_result php_uri_parser_rfc3986_userinfo_write(void *uri, zval *value, zval *errors) +zend_result php_uri_parser_rfc3986_userinfo_write(php_uri_parser_rfc3986_uris *uri, zval *value, zval *errors) { UriUriA *uriparser_uri = get_uri_for_writing(uri); int result; diff --git a/ext/uri/uri_parser_rfc3986.h b/ext/uri/uri_parser_rfc3986.h index fbbfefb30af61..4d88478b6063d 100644 --- a/ext/uri/uri_parser_rfc3986.h +++ b/ext/uri/uri_parser_rfc3986.h @@ -23,8 +23,8 @@ PHPAPI extern const php_uri_parser php_uri_parser_rfc3986; typedef struct php_uri_parser_rfc3986_uris php_uri_parser_rfc3986_uris; -zend_result php_uri_parser_rfc3986_userinfo_read(void *uri, php_uri_component_read_mode read_mode, zval *retval); -zend_result php_uri_parser_rfc3986_userinfo_write(void *uri, zval *value, zval *errors); +zend_result php_uri_parser_rfc3986_userinfo_read(php_uri_parser_rfc3986_uris *uri, php_uri_component_read_mode read_mode, zval *retval); +zend_result php_uri_parser_rfc3986_userinfo_write(php_uri_parser_rfc3986_uris *uri, zval *value, zval *errors); php_uri_parser_rfc3986_uris *php_uri_parser_rfc3986_parse_ex(const char *uri_str, size_t uri_str_len, const php_uri_parser_rfc3986_uris *uriparser_base_url, bool silent);