From 5127a229bfde5229a129b67479b5884688fc4fbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Mon, 25 Aug 2025 15:08:29 +0200 Subject: [PATCH 1/4] uri: Mark local pointers as `const` in URI parser implementations (#19581) * uri: Mark local pointers as `const` in uri_parser_whatwg.c * uri: Mark local pointers as `const` in uri_parser_rfc3986.c --- ext/uri/uri_parser_rfc3986.c | 22 +++++++++++----------- ext/uri/uri_parser_whatwg.c | 20 ++++++++++---------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/ext/uri/uri_parser_rfc3986.c b/ext/uri/uri_parser_rfc3986.c index 067df9dc822e4..ce26bcd5dabf2 100644 --- a/ext/uri/uri_parser_rfc3986.c +++ b/ext/uri/uri_parser_rfc3986.c @@ -98,7 +98,7 @@ ZEND_ATTRIBUTE_NONNULL static UriUriA *uriparser_read_uri(uriparser_uris_t *urip ZEND_ATTRIBUTE_NONNULL static zend_result uriparser_read_scheme(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { - UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + const UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); ZEND_ASSERT(uriparser_uri != NULL); if (uriparser_uri->scheme.first != NULL && uriparser_uri->scheme.afterLast != NULL) { @@ -113,7 +113,7 @@ ZEND_ATTRIBUTE_NONNULL static zend_result uriparser_read_scheme(const uri_intern ZEND_ATTRIBUTE_NONNULL zend_result uriparser_read_userinfo(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { - UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + const UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); ZEND_ASSERT(uriparser_uri != NULL); if (uriparser_uri->userInfo.first != NULL && uriparser_uri->userInfo.afterLast != NULL) { @@ -127,7 +127,7 @@ ZEND_ATTRIBUTE_NONNULL zend_result uriparser_read_userinfo(const uri_internal_t ZEND_ATTRIBUTE_NONNULL static zend_result uriparser_read_username(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { - UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + const UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); ZEND_ASSERT(uriparser_uri != NULL); if (uriparser_uri->userInfo.first != NULL && uriparser_uri->userInfo.afterLast != NULL) { @@ -150,7 +150,7 @@ ZEND_ATTRIBUTE_NONNULL static zend_result uriparser_read_username(const uri_inte ZEND_ATTRIBUTE_NONNULL static zend_result uriparser_read_password(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { - UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + const UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); ZEND_ASSERT(uriparser_uri != NULL); if (uriparser_uri->userInfo.first != NULL && uriparser_uri->userInfo.afterLast != NULL) { @@ -170,7 +170,7 @@ ZEND_ATTRIBUTE_NONNULL static zend_result uriparser_read_password(const uri_inte ZEND_ATTRIBUTE_NONNULL static zend_result uriparser_read_host(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { - UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + const UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); ZEND_ASSERT(uriparser_uri != NULL); if (uriparser_uri->hostText.first != NULL && uriparser_uri->hostText.afterLast != NULL) { @@ -206,7 +206,7 @@ ZEND_ATTRIBUTE_NONNULL static size_t str_to_int(const char *str, size_t len) ZEND_ATTRIBUTE_NONNULL static zend_result uriparser_read_port(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { - UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + const UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); ZEND_ASSERT(uriparser_uri != NULL); if (uriparser_uri->portText.first != NULL && uriparser_uri->portText.afterLast != NULL) { @@ -220,7 +220,7 @@ ZEND_ATTRIBUTE_NONNULL static zend_result uriparser_read_port(const uri_internal ZEND_ATTRIBUTE_NONNULL static zend_result uriparser_read_path(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { - UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + const UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); ZEND_ASSERT(uriparser_uri != NULL); if (uriparser_uri->pathHead != NULL) { @@ -249,7 +249,7 @@ ZEND_ATTRIBUTE_NONNULL static zend_result uriparser_read_path(const uri_internal ZEND_ATTRIBUTE_NONNULL static zend_result uriparser_read_query(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { - UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + const UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); ZEND_ASSERT(uriparser_uri != NULL); if (uriparser_uri->query.first != NULL && uriparser_uri->query.afterLast != NULL) { @@ -263,7 +263,7 @@ ZEND_ATTRIBUTE_NONNULL static zend_result uriparser_read_query(const uri_interna ZEND_ATTRIBUTE_NONNULL static zend_result uriparser_read_fragment(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { - UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + const UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); ZEND_ASSERT(uriparser_uri != NULL); if (uriparser_uri->fragment.first != NULL && uriparser_uri->fragment.afterLast != NULL) { @@ -348,7 +348,7 @@ void *uriparser_parse_uri(const char *uri_str, size_t uri_str_len, const void *b * is discarded altogether. */ ZEND_ATTRIBUTE_NONNULL static void *uriparser_clone_uri(void *uri) { - uriparser_uris_t *uriparser_uris = uri; + const uriparser_uris_t *uriparser_uris = uri; uriparser_uris_t *new_uriparser_uris = uriparser_create_uris(); uriparser_copy_uri(&new_uriparser_uris->uri, &uriparser_uris->uri); @@ -363,7 +363,7 @@ ZEND_ATTRIBUTE_NONNULL static void *uriparser_clone_uri(void *uri) ZEND_ATTRIBUTE_NONNULL static zend_string *uriparser_uri_to_string(void *uri, uri_recomposition_mode_t recomposition_mode, bool exclude_fragment) { uriparser_uris_t *uriparser_uris = uri; - UriUriA *uriparser_uri; + const UriUriA *uriparser_uri; if (recomposition_mode == URI_RECOMPOSITION_RAW_ASCII || recomposition_mode == URI_RECOMPOSITION_RAW_UNICODE) { uriparser_uri = &uriparser_uris->uri; diff --git a/ext/uri/uri_parser_whatwg.c b/ext/uri/uri_parser_whatwg.c index 4755650bd3850..66a11c3b4e9cd 100644 --- a/ext/uri/uri_parser_whatwg.c +++ b/ext/uri/uri_parser_whatwg.c @@ -260,7 +260,7 @@ static lxb_status_t lexbor_serialize_callback(const lxb_char_t *data, size_t len static zend_result lexbor_read_scheme(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { - lxb_url_t *lexbor_uri = internal_uri->uri; + const lxb_url_t *lexbor_uri = internal_uri->uri; ZEND_ASSERT(lexbor_uri->scheme.type != LXB_URL_SCHEMEL_TYPE__UNDEF); @@ -287,7 +287,7 @@ static zend_result lexbor_write_scheme(struct uri_internal_t *internal_uri, zval static zend_result lexbor_read_username(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { - lxb_url_t *lexbor_uri = internal_uri->uri; + const lxb_url_t *lexbor_uri = internal_uri->uri; if (lexbor_uri->username.length) { ZVAL_STRINGL(retval, (const char *) lexbor_uri->username.data, lexbor_uri->username.length); @@ -316,7 +316,7 @@ static zend_result lexbor_write_username(uri_internal_t *internal_uri, zval *val static zend_result lexbor_read_password(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { - lxb_url_t *lexbor_uri = internal_uri->uri; + const lxb_url_t *lexbor_uri = internal_uri->uri; if (lexbor_uri->password.length > 0) { ZVAL_STRINGL(retval, (const char *) lexbor_uri->password.data, lexbor_uri->password.length); @@ -356,7 +356,7 @@ static zend_result init_idna(void) static zend_result lexbor_read_host(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { - lxb_url_t *lexbor_uri = internal_uri->uri; + const lxb_url_t *lexbor_uri = internal_uri->uri; if (lexbor_uri->host.type == LXB_URL_HOST_TYPE_IPV4) { smart_str host_str = {0}; @@ -419,7 +419,7 @@ static zend_result lexbor_write_host(struct uri_internal_t *internal_uri, zval * static zend_result lexbor_read_port(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { - lxb_url_t *lexbor_uri = internal_uri->uri; + const lxb_url_t *lexbor_uri = internal_uri->uri; if (lexbor_uri->has_port) { ZVAL_LONG(retval, lexbor_uri->port); @@ -448,7 +448,7 @@ static zend_result lexbor_write_port(struct uri_internal_t *internal_uri, zval * static zend_result lexbor_read_path(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { - lxb_url_t *lexbor_uri = internal_uri->uri; + const lxb_url_t *lexbor_uri = internal_uri->uri; if (lexbor_uri->path.str.length) { ZVAL_STRINGL(retval, (const char *) lexbor_uri->path.str.data, lexbor_uri->path.str.length); @@ -477,7 +477,7 @@ static zend_result lexbor_write_path(struct uri_internal_t *internal_uri, zval * static zend_result lexbor_read_query(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { - lxb_url_t *lexbor_uri = internal_uri->uri; + const lxb_url_t *lexbor_uri = internal_uri->uri; if (lexbor_uri->query.length) { ZVAL_STRINGL(retval, (const char *) lexbor_uri->query.data, lexbor_uri->query.length); @@ -506,7 +506,7 @@ static zend_result lexbor_write_query(struct uri_internal_t *internal_uri, zval static zend_result lexbor_read_fragment(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { - lxb_url_t *lexbor_uri = internal_uri->uri; + const lxb_url_t *lexbor_uri = internal_uri->uri; if (lexbor_uri->fragment.length) { ZVAL_STRINGL(retval, (const char *) lexbor_uri->fragment.data, lexbor_uri->fragment.length); @@ -586,14 +586,14 @@ static void *lexbor_parse_uri(const char *uri_str, size_t uri_str_len, const voi static void *lexbor_clone_uri(void *uri) { - lxb_url_t *lexbor_uri = (lxb_url_t *) uri; + const lxb_url_t *lexbor_uri = uri; return lxb_url_clone(lexbor_parser.mraw, lexbor_uri); } static zend_string *lexbor_uri_to_string(void *uri, uri_recomposition_mode_t recomposition_mode, bool exclude_fragment) { - lxb_url_t *lexbor_uri = (lxb_url_t *) uri; + const lxb_url_t *lexbor_uri = uri; smart_str uri_str = {0}; switch (recomposition_mode) { From 6497c6c455ef0cb2debe1891d6c6d00ece95a3c2 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Wed, 20 Aug 2025 23:20:47 +0200 Subject: [PATCH 2/4] Don't substitute self/parent with anonymous class Fixes GH-18373 Closes GH-19537 --- NEWS | 2 ++ Zend/tests/gh19304.phpt | 2 +- Zend/zend_compile.c | 8 ++++++-- ext/reflection/tests/gh18373.phpt | 14 ++++++++++++++ 4 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 ext/reflection/tests/gh18373.phpt diff --git a/NEWS b/NEWS index 6c2db856000e3..3bcc968bab6cf 100644 --- a/NEWS +++ b/NEWS @@ -25,6 +25,8 @@ PHP NEWS operators" RFC, meaning that incrementing non-numeric strings is now deprecated. (Girgias). . Various closure binding issues are now deprecated. (alexandre-daubois) + . Fixed bug GH-18373 (Don't substitute self/parent with anonymous class). + (ilutov) - Filter: . Added support for configuring the URI parser for FILTER_VALIDATE_URL diff --git a/Zend/tests/gh19304.phpt b/Zend/tests/gh19304.phpt index c77fc2d6facc2..47e20af64623a 100644 --- a/Zend/tests/gh19304.phpt +++ b/Zend/tests/gh19304.phpt @@ -15,4 +15,4 @@ try { ?> --EXPECT-- -Cannot assign int to property class@anonymous::$v of type class@anonymous +Cannot assign int to property class@anonymous::$v of type self diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 205023fa69b64..503b469974224 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -7091,16 +7091,20 @@ static zend_type zend_compile_single_typename(zend_ast *ast) ZEND_ASSERT(fetch_type == ZEND_FETCH_CLASS_SELF || fetch_type == ZEND_FETCH_CLASS_PARENT); zend_ensure_valid_class_fetch_type(fetch_type); + + bool substitute_self_parent = zend_is_scope_known() + && !(CG(active_class_entry)->ce_flags & ZEND_ACC_ANON_CLASS); + if (fetch_type == ZEND_FETCH_CLASS_SELF) { /* Scope might be unknown for unbound closures and traits */ - if (zend_is_scope_known()) { + if (substitute_self_parent) { class_name = CG(active_class_entry)->name; ZEND_ASSERT(class_name && "must know class name when resolving self type at compile time"); } } else { ZEND_ASSERT(fetch_type == ZEND_FETCH_CLASS_PARENT); /* Scope might be unknown for unbound closures and traits */ - if (zend_is_scope_known()) { + if (substitute_self_parent) { class_name = CG(active_class_entry)->parent_name; ZEND_ASSERT(class_name && "must know class name when resolving parent type at compile time"); } diff --git a/ext/reflection/tests/gh18373.phpt b/ext/reflection/tests/gh18373.phpt new file mode 100644 index 0000000000000..30aa1a0f5fe54 --- /dev/null +++ b/ext/reflection/tests/gh18373.phpt @@ -0,0 +1,14 @@ +--TEST-- +GH-18373: Don't substitute self/parent with anonymous class +--FILE-- +getMethod('test')->getReturnType()->getName(), "\n"; + +?> +--EXPECT-- +self From 71a3226a46735e0ee8f0976774181c0502cfd2ed Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Thu, 14 Aug 2025 23:17:01 +0200 Subject: [PATCH 3/4] Prohibit pipe & arrow function combination that leads to confusing parse trees See https://externals.io/message/128473 Closes GH-19533 --- NEWS | 2 ++ Zend/tests/arrow_functions/gh7900.phpt | 2 +- .../pipe_operator/mixed_callable_call.phpt | 2 +- Zend/tests/pipe_operator/prec_001.phpt | 12 ++++++++++ Zend/tests/pipe_operator/prec_002.phpt | 12 ++++++++++ Zend/tests/pipe_operator/prec_003.phpt | 12 ++++++++++ Zend/tests/pipe_operator/prec_004.phpt | 16 +++++++++++++ Zend/tests/pipe_operator/prec_005.phpt | 14 +++++++++++ Zend/tests/pipe_operator/prec_006.phpt | 13 ++++++++++ Zend/tests/pipe_operator/prec_007.phpt | 24 +++++++++++++++++++ Zend/zend_ast.c | 6 +++++ Zend/zend_ast.h | 2 +- Zend/zend_compile.c | 4 ++++ Zend/zend_compile.h | 3 +++ Zend/zend_language_parser.y | 1 + 15 files changed, 122 insertions(+), 3 deletions(-) create mode 100644 Zend/tests/pipe_operator/prec_001.phpt create mode 100644 Zend/tests/pipe_operator/prec_002.phpt create mode 100644 Zend/tests/pipe_operator/prec_003.phpt create mode 100644 Zend/tests/pipe_operator/prec_004.phpt create mode 100644 Zend/tests/pipe_operator/prec_005.phpt create mode 100644 Zend/tests/pipe_operator/prec_006.phpt create mode 100644 Zend/tests/pipe_operator/prec_007.phpt diff --git a/NEWS b/NEWS index 3bcc968bab6cf..f8b4fca0d20b8 100644 --- a/NEWS +++ b/NEWS @@ -27,6 +27,8 @@ PHP NEWS . Various closure binding issues are now deprecated. (alexandre-daubois) . Fixed bug GH-18373 (Don't substitute self/parent with anonymous class). (ilutov) + . Prohibit pipe & arrow function combination that leads to confusing parse + trees. (ilutov) - Filter: . Added support for configuring the URI parser for FILTER_VALIDATE_URL diff --git a/Zend/tests/arrow_functions/gh7900.phpt b/Zend/tests/arrow_functions/gh7900.phpt index a4170fb1278fc..d6465c312399c 100644 --- a/Zend/tests/arrow_functions/gh7900.phpt +++ b/Zend/tests/arrow_functions/gh7900.phpt @@ -23,4 +23,4 @@ try { ?> --EXPECT-- Here -assert(fn(): never => 42 && false) +assert((fn(): never => 42) && false) diff --git a/Zend/tests/pipe_operator/mixed_callable_call.phpt b/Zend/tests/pipe_operator/mixed_callable_call.phpt index 55bae626f1890..d577f3aaefe69 100644 --- a/Zend/tests/pipe_operator/mixed_callable_call.phpt +++ b/Zend/tests/pipe_operator/mixed_callable_call.phpt @@ -71,7 +71,7 @@ $res1 = 1 |> [StaticTest::class, 'times17'] |> new Times23() |> $times29 - |> fn($x) => times2($x) + |> (fn($x) => times2($x)) ; var_dump($res1); diff --git a/Zend/tests/pipe_operator/prec_001.phpt b/Zend/tests/pipe_operator/prec_001.phpt new file mode 100644 index 0000000000000..3bd3397fd3617 --- /dev/null +++ b/Zend/tests/pipe_operator/prec_001.phpt @@ -0,0 +1,12 @@ +--TEST-- +Pipe precedence 001 +--FILE-- + fn($x) => $x < 42 + |> fn($x) => var_dump($x); + +?> +--EXPECTF-- +Fatal error: Arrow functions on the right hand side of |> must be parenthesized in %s on line %d diff --git a/Zend/tests/pipe_operator/prec_002.phpt b/Zend/tests/pipe_operator/prec_002.phpt new file mode 100644 index 0000000000000..00a16e61fed4b --- /dev/null +++ b/Zend/tests/pipe_operator/prec_002.phpt @@ -0,0 +1,12 @@ +--TEST-- +Pipe precedence 002 +--FILE-- + (fn($x) => $x < 42) + |> (fn($x) => var_dump($x)); + +?> +--EXPECT-- +bool(false) diff --git a/Zend/tests/pipe_operator/prec_003.phpt b/Zend/tests/pipe_operator/prec_003.phpt new file mode 100644 index 0000000000000..9200b8014e09f --- /dev/null +++ b/Zend/tests/pipe_operator/prec_003.phpt @@ -0,0 +1,12 @@ +--TEST-- +Pipe precedence 003 +--FILE-- + fn() => print (new Exception)->getTraceAsString() . "\n\n" + |> fn() => print (new Exception)->getTraceAsString() . "\n\n"; + +?> +--EXPECTF-- +Fatal error: Arrow functions on the right hand side of |> must be parenthesized in %s on line %d diff --git a/Zend/tests/pipe_operator/prec_004.phpt b/Zend/tests/pipe_operator/prec_004.phpt new file mode 100644 index 0000000000000..c04f483cdd8db --- /dev/null +++ b/Zend/tests/pipe_operator/prec_004.phpt @@ -0,0 +1,16 @@ +--TEST-- +Pipe precedence 004 +--FILE-- + (fn() => print (new Exception)->getTraceAsString() . "\n\n") + |> (fn() => print (new Exception)->getTraceAsString() . "\n\n"); + +?> +--EXPECTF-- +#0 %s(%d): {closure:%s:%d}(NULL) +#1 {main} + +#0 %s(%d): {closure:%s:%d}(1) +#1 {main} diff --git a/Zend/tests/pipe_operator/prec_005.phpt b/Zend/tests/pipe_operator/prec_005.phpt new file mode 100644 index 0000000000000..0dd262324e3d2 --- /dev/null +++ b/Zend/tests/pipe_operator/prec_005.phpt @@ -0,0 +1,14 @@ +--TEST-- +Pipe precedence 005 +--FILE-- + (fn() => 2)); +} catch (AssertionError $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +assert(false && 1 |> (fn() => 2)) diff --git a/Zend/tests/pipe_operator/prec_006.phpt b/Zend/tests/pipe_operator/prec_006.phpt new file mode 100644 index 0000000000000..d7fdf4c9b55b1 --- /dev/null +++ b/Zend/tests/pipe_operator/prec_006.phpt @@ -0,0 +1,13 @@ +--TEST-- +Pipe precedence 006 +--FILE-- + fn ($x) => $x ?? throw new Exception('Value may not be null') + |> fn ($x) => var_dump($x); + +?> +--EXPECTF-- +Fatal error: Arrow functions on the right hand side of |> must be parenthesized in %s on line %d diff --git a/Zend/tests/pipe_operator/prec_007.phpt b/Zend/tests/pipe_operator/prec_007.phpt new file mode 100644 index 0000000000000..c29db8565008f --- /dev/null +++ b/Zend/tests/pipe_operator/prec_007.phpt @@ -0,0 +1,24 @@ +--TEST-- +Pipe precedence 007 +--FILE-- + (fn ($x) => $x ?? throw new Exception('Value may not be null')) + |> (fn ($x) => var_dump($x)); + +$value = null; +$value + |> (fn ($x) => $x ?? throw new Exception('Value may not be null')) + |> (fn ($x) => var_dump($x)); + +?> +--EXPECTF-- +int(42) + +Fatal error: Uncaught Exception: Value may not be null in %s:%d +Stack trace: +#0 %s(%d): {closure:%s:%d}(NULL) +#1 {main} + thrown in %s on line %d diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index 1172cba2d4f16..fd2526fb5e667 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -2070,6 +2070,9 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio case ZEND_AST_ARROW_FUNC: case ZEND_AST_METHOD: decl = (const zend_ast_decl *) ast; + if (decl->kind == ZEND_AST_ARROW_FUNC && (decl->attr & ZEND_PARENTHESIZED_ARROW_FUNC)) { + smart_str_appendc(str, '('); + } if (decl->child[4]) { bool newlines = !(ast->kind == ZEND_AST_CLOSURE || ast->kind == ZEND_AST_ARROW_FUNC); zend_ast_export_attributes(str, decl->child[4], indent, newlines); @@ -2113,6 +2116,9 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio } smart_str_appends(str, " => "); zend_ast_export_ex(str, body, 0, indent); + if (decl->attr & ZEND_PARENTHESIZED_ARROW_FUNC) { + smart_str_appendc(str, ')'); + } break; } diff --git a/Zend/zend_ast.h b/Zend/zend_ast.h index 2e561f225917a..8ce1c49f6bb0c 100644 --- a/Zend/zend_ast.h +++ b/Zend/zend_ast.h @@ -220,7 +220,7 @@ typedef struct _zend_ast_op_array { /* Separate structure for function and class declaration, as they need extra information. */ typedef struct _zend_ast_decl { zend_ast_kind kind; - zend_ast_attr attr; /* Unused - for structure compatibility */ + zend_ast_attr attr; uint32_t start_lineno; uint32_t end_lineno; uint32_t flags; diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 503b469974224..fae510bb2688c 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -6467,6 +6467,10 @@ static void zend_compile_pipe(znode *result, zend_ast *ast) zend_ast *operand_ast = ast->child[0]; zend_ast *callable_ast = ast->child[1]; + if (callable_ast->kind == ZEND_AST_ARROW_FUNC && !(callable_ast->attr & ZEND_PARENTHESIZED_ARROW_FUNC)) { + zend_error_noreturn(E_COMPILE_ERROR, "Arrow functions on the right hand side of |> must be parenthesized"); + } + /* Compile the left hand side down to a value first. */ znode operand_result; zend_compile_expr(&operand_result, operand_ast); diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 84afd44341928..0234f77775b33 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -1207,6 +1207,9 @@ static zend_always_inline bool zend_check_arg_send_type(const zend_function *zf, /* Used to distinguish (parent::$prop)::get() from parent hook call. */ #define ZEND_PARENTHESIZED_STATIC_PROP 1 +/* Used to disallow pipes with arrow functions that lead to confusing parse trees. */ +#define ZEND_PARENTHESIZED_ARROW_FUNC 1 + /* For "use" AST nodes and the seen symbol table */ #define ZEND_SYMBOL_CLASS (1<<0) #define ZEND_SYMBOL_FUNCTION (1<<1) diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 3f2817b26ec44..e4d61006fe12f 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -1348,6 +1348,7 @@ expr: | '(' expr ')' { $$ = $2; if ($$->kind == ZEND_AST_CONDITIONAL) $$->attr = ZEND_PARENTHESIZED_CONDITIONAL; + if ($$->kind == ZEND_AST_ARROW_FUNC) $$->attr = ZEND_PARENTHESIZED_ARROW_FUNC; } | new_dereferenceable { $$ = $1; } | new_non_dereferenceable { $$ = $1; } From 5d5305d99dddbfb7d581c2e06220b77249049573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Mon, 25 Aug 2025 18:58:00 +0200 Subject: [PATCH 4/4] uri: Properly prefix symbols in uri_parser_*.[ch] (#19554) * uri: Remove unnecessary forward declaration of `uriparser_free_uri()` * uri: Properly prefix symbols in uri_parser_rfc3986.[ch] * uri: Make `#define`s in uri_parser_whatwg proper typed constants * uri: Properly prefix symbols in uri_parser_whatwg.[ch] * NEWS --- NEWS | 4 ++ ext/uri/php_uri.c | 14 ++-- ext/uri/php_uri_common.h | 4 +- ext/uri/uri_parser_rfc3986.c | 128 +++++++++++++++++------------------ ext/uri/uri_parser_rfc3986.h | 10 +-- ext/uri/uri_parser_whatwg.c | 118 ++++++++++++++++---------------- ext/uri/uri_parser_whatwg.h | 4 +- 7 files changed, 142 insertions(+), 140 deletions(-) diff --git a/NEWS b/NEWS index f8b4fca0d20b8..1a2369ea2d073 100644 --- a/NEWS +++ b/NEWS @@ -69,6 +69,10 @@ PHP NEWS . Fixed bug GH-19507 (Corrupted result after recursive tokenization during token_get_all()). (kubawerlos, nielsdos, Arnaud) +- URI: + . Clean up naming of internal API (header names, symbol names). + (Máté Kocsis, timwolla) + 14 Aug 2025, PHP 8.5.0beta1 - Core: diff --git a/ext/uri/php_uri.c b/ext/uri/php_uri.c index d6fbac50c78ad..e440ba8b8829c 100644 --- a/ext/uri/php_uri.c +++ b/ext/uri/php_uri.c @@ -393,7 +393,7 @@ static void create_rfc3986_uri(INTERNAL_FUNCTION_PARAMETERS, bool is_constructor Z_PARAM_OBJ_OF_CLASS_OR_NULL(base_url_object, uri_rfc3986_uri_ce) ZEND_PARSE_PARAMETERS_END(); - php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, &uriparser_uri_parser, uri_str, base_url_object, is_constructor, is_constructor, NULL); + php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, &php_uri_parser_rfc3986, uri_str, base_url_object, is_constructor, is_constructor, NULL); } PHP_METHOD(Uri_Rfc3986_Uri, parse) @@ -480,7 +480,7 @@ static void create_whatwg_uri(INTERNAL_FUNCTION_PARAMETERS, bool is_constructor) Z_PARAM_ZVAL(errors) ZEND_PARSE_PARAMETERS_END(); - php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, &lexbor_uri_parser, uri_str, base_url_object, is_constructor, is_constructor, errors); + php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, &php_uri_parser_whatwg, uri_str, base_url_object, is_constructor, is_constructor, errors); } PHP_METHOD(Uri_WhatWg_Url, parse) @@ -510,7 +510,7 @@ static void read_uriparser_userinfo(INTERNAL_FUNCTION_PARAMETERS, uri_component_ uri_internal_t *internal_uri = Z_URI_INTERNAL_P(ZEND_THIS); URI_ASSERT_INITIALIZATION(internal_uri); - if (UNEXPECTED(uriparser_read_userinfo(internal_uri, read_mode, return_value) == FAILURE)) { + if (UNEXPECTED(php_uri_parser_rfc3986_userinfo_read(internal_uri, read_mode, return_value) == FAILURE)) { zend_throw_error(NULL, "The userinfo component cannot be retrieved"); RETURN_THROWS(); } @@ -794,7 +794,7 @@ static void uri_unserialize(INTERNAL_FUNCTION_PARAMETERS, const char *uri_parser PHP_METHOD(Uri_Rfc3986_Uri, __unserialize) { - uri_unserialize(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PARSER_RFC3986); + uri_unserialize(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PARSER_RFC3986); } PHP_METHOD(Uri_Rfc3986_Uri, __debugInfo) @@ -947,7 +947,7 @@ PHP_METHOD(Uri_WhatWg_Url, __serialize) PHP_METHOD(Uri_WhatWg_Url, __unserialize) { - uri_unserialize(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PARSER_WHATWG); + uri_unserialize(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PARSER_WHATWG); } PHP_METHOD(Uri_WhatWg_Url, __debugInfo) @@ -1049,11 +1049,11 @@ static PHP_MINIT_FUNCTION(uri) zend_hash_init(&uri_parsers, 4, NULL, NULL, true); - if (php_uri_parser_register(&uriparser_uri_parser) == FAILURE) { + if (php_uri_parser_register(&php_uri_parser_rfc3986) == FAILURE) { return FAILURE; } - if (php_uri_parser_register(&lexbor_uri_parser) == FAILURE) { + if (php_uri_parser_register(&php_uri_parser_whatwg) == FAILURE) { return FAILURE; } diff --git a/ext/uri/php_uri_common.h b/ext/uri/php_uri_common.h index e18777a8673fc..afffdfb8f5cf0 100644 --- a/ext/uri/php_uri_common.h +++ b/ext/uri/php_uri_common.h @@ -162,8 +162,8 @@ static inline uri_internal_t *uri_internal_from_obj(const zend_object *object) { #define Z_URI_OBJECT_P(zv) uri_object_from_obj(Z_OBJ_P((zv))) #define Z_URI_INTERNAL_P(zv) uri_internal_from_obj(Z_OBJ_P((zv))) -#define URI_PARSER_RFC3986 "Uri\\Rfc3986\\Uri" -#define URI_PARSER_WHATWG "Uri\\WhatWg\\Url" +#define PHP_URI_PARSER_RFC3986 "Uri\\Rfc3986\\Uri" +#define PHP_URI_PARSER_WHATWG "Uri\\WhatWg\\Url" #define URI_PARSER_PHP "parse_url" #define URI_SERIALIZED_PROPERTY_NAME "uri" diff --git a/ext/uri/uri_parser_rfc3986.c b/ext/uri/uri_parser_rfc3986.c index ce26bcd5dabf2..fd21308bedee7 100644 --- a/ext/uri/uri_parser_rfc3986.c +++ b/ext/uri/uri_parser_rfc3986.c @@ -20,61 +20,59 @@ #include "Zend/zend_smart_str.h" #include "Zend/zend_exceptions.h" -static void uriparser_free_uri(void *uri); - -static void *uriparser_malloc(UriMemoryManager *memory_manager, size_t size) +static void *php_uri_parser_rfc3986_memory_manager_malloc(UriMemoryManager *memory_manager, size_t size) { return emalloc(size); } -static void *uriparser_calloc(UriMemoryManager *memory_manager, size_t nmemb, size_t size) +static void *php_uri_parser_rfc3986_memory_manager_calloc(UriMemoryManager *memory_manager, size_t nmemb, size_t size) { return ecalloc(nmemb, size); } -static void *uriparser_realloc(UriMemoryManager *memory_manager, void *ptr, size_t size) +static void *php_uri_parser_rfc3986_memory_manager_realloc(UriMemoryManager *memory_manager, void *ptr, size_t size) { return erealloc(ptr, size); } -static void *uriparser_reallocarray(UriMemoryManager *memory_manager, void *ptr, size_t nmemb, size_t size) +static void *php_uri_parser_rfc3986_memory_manager_reallocarray(UriMemoryManager *memory_manager, void *ptr, size_t nmemb, size_t size) { return safe_erealloc(ptr, nmemb, size, 0); } -static void uriparser_free(UriMemoryManager *memory_manager, void *ptr) +static void php_uri_parser_rfc3986_memory_manager_free(UriMemoryManager *memory_manager, void *ptr) { efree(ptr); } -static const UriMemoryManager uriparser_mm = { - .malloc = uriparser_malloc, - .calloc = uriparser_calloc, - .realloc = uriparser_realloc, - .reallocarray = uriparser_reallocarray, - .free = uriparser_free, +static const UriMemoryManager php_uri_parser_rfc3986_memory_manager = { + .malloc = php_uri_parser_rfc3986_memory_manager_malloc, + .calloc = php_uri_parser_rfc3986_memory_manager_calloc, + .realloc = php_uri_parser_rfc3986_memory_manager_realloc, + .reallocarray = php_uri_parser_rfc3986_memory_manager_reallocarray, + .free = php_uri_parser_rfc3986_memory_manager_free, .userData = NULL, }; /* The library expects a pointer to a non-const UriMemoryManager, but does * not actually modify it (and neither does our implementation). Use a * const struct with a non-const pointer for convenience. */ -static UriMemoryManager* const mm = (UriMemoryManager*)&uriparser_mm; +static UriMemoryManager* const mm = (UriMemoryManager*)&php_uri_parser_rfc3986_memory_manager; static inline size_t get_text_range_length(const UriTextRangeA *range) { return range->afterLast - range->first; } -ZEND_ATTRIBUTE_NONNULL static void uriparser_copy_uri(UriUriA *new_uriparser_uri, const UriUriA *uriparser_uri) +ZEND_ATTRIBUTE_NONNULL static void copy_uri(UriUriA *new_uriparser_uri, const UriUriA *uriparser_uri) { int result = uriCopyUriMmA(new_uriparser_uri, uriparser_uri, mm); ZEND_ASSERT(result == URI_SUCCESS); } -ZEND_ATTRIBUTE_NONNULL static UriUriA *get_normalized_uri(uriparser_uris_t *uriparser_uris) { +ZEND_ATTRIBUTE_NONNULL static UriUriA *get_normalized_uri(php_uri_parser_rfc3986_uris *uriparser_uris) { if (!uriparser_uris->normalized_uri_initialized) { - uriparser_copy_uri(&uriparser_uris->normalized_uri, &uriparser_uris->uri); + copy_uri(&uriparser_uris->normalized_uri, &uriparser_uris->uri); int result = uriNormalizeSyntaxExMmA(&uriparser_uris->normalized_uri, (unsigned int)-1, mm); ZEND_ASSERT(result == URI_SUCCESS); uriparser_uris->normalized_uri_initialized = true; @@ -83,7 +81,7 @@ ZEND_ATTRIBUTE_NONNULL static UriUriA *get_normalized_uri(uriparser_uris_t *urip return &uriparser_uris->normalized_uri; } -ZEND_ATTRIBUTE_NONNULL static UriUriA *uriparser_read_uri(uriparser_uris_t *uriparser_uris, uri_component_read_mode_t read_mode) +ZEND_ATTRIBUTE_NONNULL static UriUriA *get_uri_for_reading(php_uri_parser_rfc3986_uris *uriparser_uris, uri_component_read_mode_t read_mode) { switch (read_mode) { case URI_COMPONENT_READ_RAW: @@ -96,9 +94,9 @@ ZEND_ATTRIBUTE_NONNULL static UriUriA *uriparser_read_uri(uriparser_uris_t *urip } } -ZEND_ATTRIBUTE_NONNULL static zend_result uriparser_read_scheme(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_scheme_read(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { - const UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + const UriUriA *uriparser_uri = get_uri_for_reading(internal_uri->uri, read_mode); ZEND_ASSERT(uriparser_uri != NULL); if (uriparser_uri->scheme.first != NULL && uriparser_uri->scheme.afterLast != NULL) { @@ -111,9 +109,9 @@ ZEND_ATTRIBUTE_NONNULL static zend_result uriparser_read_scheme(const uri_intern return SUCCESS; } -ZEND_ATTRIBUTE_NONNULL zend_result uriparser_read_userinfo(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +ZEND_ATTRIBUTE_NONNULL zend_result php_uri_parser_rfc3986_userinfo_read(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { - const UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + const UriUriA *uriparser_uri = get_uri_for_reading(internal_uri->uri, read_mode); ZEND_ASSERT(uriparser_uri != NULL); if (uriparser_uri->userInfo.first != NULL && uriparser_uri->userInfo.afterLast != NULL) { @@ -125,9 +123,9 @@ ZEND_ATTRIBUTE_NONNULL zend_result uriparser_read_userinfo(const uri_internal_t return SUCCESS; } -ZEND_ATTRIBUTE_NONNULL static zend_result uriparser_read_username(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_username_read(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { - const UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + const UriUriA *uriparser_uri = get_uri_for_reading(internal_uri->uri, read_mode); ZEND_ASSERT(uriparser_uri != NULL); if (uriparser_uri->userInfo.first != NULL && uriparser_uri->userInfo.afterLast != NULL) { @@ -148,9 +146,9 @@ ZEND_ATTRIBUTE_NONNULL static zend_result uriparser_read_username(const uri_inte return SUCCESS; } -ZEND_ATTRIBUTE_NONNULL static zend_result uriparser_read_password(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_password_read(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { - const UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + const UriUriA *uriparser_uri = get_uri_for_reading(internal_uri->uri, read_mode); ZEND_ASSERT(uriparser_uri != NULL); if (uriparser_uri->userInfo.first != NULL && uriparser_uri->userInfo.afterLast != NULL) { @@ -168,9 +166,9 @@ ZEND_ATTRIBUTE_NONNULL static zend_result uriparser_read_password(const uri_inte return SUCCESS; } -ZEND_ATTRIBUTE_NONNULL static zend_result uriparser_read_host(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_host_read(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { - const UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + const UriUriA *uriparser_uri = get_uri_for_reading(internal_uri->uri, read_mode); ZEND_ASSERT(uriparser_uri != NULL); if (uriparser_uri->hostText.first != NULL && uriparser_uri->hostText.afterLast != NULL) { @@ -204,9 +202,9 @@ ZEND_ATTRIBUTE_NONNULL static size_t str_to_int(const char *str, size_t len) return result; } -ZEND_ATTRIBUTE_NONNULL static zend_result uriparser_read_port(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_port_read(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { - const UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + const UriUriA *uriparser_uri = get_uri_for_reading(internal_uri->uri, read_mode); ZEND_ASSERT(uriparser_uri != NULL); if (uriparser_uri->portText.first != NULL && uriparser_uri->portText.afterLast != NULL) { @@ -218,9 +216,9 @@ ZEND_ATTRIBUTE_NONNULL static zend_result uriparser_read_port(const uri_internal return SUCCESS; } -ZEND_ATTRIBUTE_NONNULL static zend_result uriparser_read_path(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_path_read(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { - const UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + const UriUriA *uriparser_uri = get_uri_for_reading(internal_uri->uri, read_mode); ZEND_ASSERT(uriparser_uri != NULL); if (uriparser_uri->pathHead != NULL) { @@ -247,9 +245,9 @@ ZEND_ATTRIBUTE_NONNULL static zend_result uriparser_read_path(const uri_internal return SUCCESS; } -ZEND_ATTRIBUTE_NONNULL static zend_result uriparser_read_query(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_query_read(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { - const UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + const UriUriA *uriparser_uri = get_uri_for_reading(internal_uri->uri, read_mode); ZEND_ASSERT(uriparser_uri != NULL); if (uriparser_uri->query.first != NULL && uriparser_uri->query.afterLast != NULL) { @@ -261,9 +259,9 @@ ZEND_ATTRIBUTE_NONNULL static zend_result uriparser_read_query(const uri_interna return SUCCESS; } -ZEND_ATTRIBUTE_NONNULL static zend_result uriparser_read_fragment(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_fragment_read(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { - const UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + const UriUriA *uriparser_uri = get_uri_for_reading(internal_uri->uri, read_mode); ZEND_ASSERT(uriparser_uri != NULL); if (uriparser_uri->fragment.first != NULL && uriparser_uri->fragment.afterLast != NULL) { @@ -275,15 +273,15 @@ ZEND_ATTRIBUTE_NONNULL static zend_result uriparser_read_fragment(const uri_inte return SUCCESS; } -static uriparser_uris_t *uriparser_create_uris(void) +static php_uri_parser_rfc3986_uris *uriparser_create_uris(void) { - uriparser_uris_t *uriparser_uris = ecalloc(1, sizeof(*uriparser_uris)); + php_uri_parser_rfc3986_uris *uriparser_uris = ecalloc(1, sizeof(*uriparser_uris)); uriparser_uris->normalized_uri_initialized = false; return uriparser_uris; } -uriparser_uris_t *uriparser_parse_uri_ex(const char *uri_str, size_t uri_str_len, const uriparser_uris_t *uriparser_base_urls, bool silent) +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_urls, bool silent) { UriUriA uri = {0}; @@ -326,7 +324,7 @@ uriparser_uris_t *uriparser_parse_uri_ex(const char *uri_str, size_t uri_str_len /* Make the resulting URI independent of the 'uri_str'. */ uriMakeOwnerMmA(&uri, mm); - uriparser_uris_t *uriparser_uris = uriparser_create_uris(); + php_uri_parser_rfc3986_uris *uriparser_uris = uriparser_create_uris(); uriparser_uris->uri = uri; return uriparser_uris; @@ -338,31 +336,31 @@ uriparser_uris_t *uriparser_parse_uri_ex(const char *uri_str, size_t uri_str_len return NULL; } -void *uriparser_parse_uri(const char *uri_str, size_t uri_str_len, const void *base_url, zval *errors, bool silent) +void *php_uri_parser_rfc3986_parse(const char *uri_str, size_t uri_str_len, const void *base_url, zval *errors, bool silent) { - return uriparser_parse_uri_ex(uri_str, uri_str_len, base_url, silent); + return php_uri_parser_rfc3986_parse_ex(uri_str, uri_str_len, base_url, silent); } /* When calling a wither successfully, the normalized URI is surely invalidated, therefore * it doesn't make sense to copy it. In case of failure, an exception is thrown, and the URI object * is discarded altogether. */ -ZEND_ATTRIBUTE_NONNULL static void *uriparser_clone_uri(void *uri) +ZEND_ATTRIBUTE_NONNULL static void *php_uri_parser_rfc3986_clone(void *uri) { - const uriparser_uris_t *uriparser_uris = uri; + const php_uri_parser_rfc3986_uris *uriparser_uris = uri; - uriparser_uris_t *new_uriparser_uris = uriparser_create_uris(); - uriparser_copy_uri(&new_uriparser_uris->uri, &uriparser_uris->uri); + php_uri_parser_rfc3986_uris *new_uriparser_uris = uriparser_create_uris(); + copy_uri(&new_uriparser_uris->uri, &uriparser_uris->uri); if (uriparser_uris->normalized_uri_initialized) { - uriparser_copy_uri(&new_uriparser_uris->normalized_uri, &uriparser_uris->normalized_uri); + copy_uri(&new_uriparser_uris->normalized_uri, &uriparser_uris->normalized_uri); new_uriparser_uris->normalized_uri_initialized = true; } return new_uriparser_uris; } -ZEND_ATTRIBUTE_NONNULL static zend_string *uriparser_uri_to_string(void *uri, uri_recomposition_mode_t recomposition_mode, bool exclude_fragment) +ZEND_ATTRIBUTE_NONNULL static zend_string *php_uri_parser_rfc3986_to_string(void *uri, uri_recomposition_mode_t recomposition_mode, bool exclude_fragment) { - uriparser_uris_t *uriparser_uris = uri; + php_uri_parser_rfc3986_uris *uriparser_uris = uri; const UriUriA *uriparser_uri; if (recomposition_mode == URI_RECOMPOSITION_RAW_ASCII || recomposition_mode == URI_RECOMPOSITION_RAW_UNICODE) { @@ -391,9 +389,9 @@ ZEND_ATTRIBUTE_NONNULL static zend_string *uriparser_uri_to_string(void *uri, ur return uri_string; } -ZEND_ATTRIBUTE_NONNULL static void uriparser_free_uri(void *uri) +ZEND_ATTRIBUTE_NONNULL static void php_uri_parser_rfc3986_free(void *uri) { - uriparser_uris_t *uriparser_uris = uri; + php_uri_parser_rfc3986_uris *uriparser_uris = uri; uriFreeUriMembersMmA(&uriparser_uris->uri, mm); uriFreeUriMembersMmA(&uriparser_uris->normalized_uri, mm); @@ -401,20 +399,20 @@ ZEND_ATTRIBUTE_NONNULL static void uriparser_free_uri(void *uri) efree(uriparser_uris); } -const uri_parser_t uriparser_uri_parser = { - .name = URI_PARSER_RFC3986, - .parse_uri = uriparser_parse_uri, - .clone_uri = uriparser_clone_uri, - .uri_to_string = uriparser_uri_to_string, - .free_uri = uriparser_free_uri, +const uri_parser_t php_uri_parser_rfc3986 = { + .name = PHP_URI_PARSER_RFC3986, + .parse_uri = php_uri_parser_rfc3986_parse, + .clone_uri = php_uri_parser_rfc3986_clone, + .uri_to_string = php_uri_parser_rfc3986_to_string, + .free_uri = php_uri_parser_rfc3986_free, { - .scheme = {.read_func = uriparser_read_scheme, .write_func = NULL}, - .username = {.read_func = uriparser_read_username, .write_func = NULL}, - .password = {.read_func = uriparser_read_password, .write_func = NULL}, - .host = {.read_func = uriparser_read_host, .write_func = NULL}, - .port = {.read_func = uriparser_read_port, .write_func = NULL}, - .path = {.read_func = uriparser_read_path, .write_func = NULL}, - .query = {.read_func = uriparser_read_query, .write_func = NULL}, - .fragment = {.read_func = uriparser_read_fragment, .write_func = NULL}, + .scheme = {.read_func = php_uri_parser_rfc3986_scheme_read, .write_func = NULL}, + .username = {.read_func = php_uri_parser_rfc3986_username_read, .write_func = NULL}, + .password = {.read_func = php_uri_parser_rfc3986_password_read, .write_func = NULL}, + .host = {.read_func = php_uri_parser_rfc3986_host_read, .write_func = NULL}, + .port = {.read_func = php_uri_parser_rfc3986_port_read, .write_func = NULL}, + .path = {.read_func = php_uri_parser_rfc3986_path_read, .write_func = NULL}, + .query = {.read_func = php_uri_parser_rfc3986_query_read, .write_func = NULL}, + .fragment = {.read_func = php_uri_parser_rfc3986_fragment_read, .write_func = NULL}, } }; diff --git a/ext/uri/uri_parser_rfc3986.h b/ext/uri/uri_parser_rfc3986.h index e15cf803ecc0e..461136a9f06cc 100644 --- a/ext/uri/uri_parser_rfc3986.h +++ b/ext/uri/uri_parser_rfc3986.h @@ -20,16 +20,16 @@ #include #include "php_uri_common.h" -extern const uri_parser_t uriparser_uri_parser; +extern const uri_parser_t php_uri_parser_rfc3986; -typedef struct uriparser_uris_t { +typedef struct php_uri_parser_rfc3986_uris { UriUriA uri; UriUriA normalized_uri; bool normalized_uri_initialized; -} uriparser_uris_t; +} php_uri_parser_rfc3986_uris; -zend_result uriparser_read_userinfo(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval); +zend_result php_uri_parser_rfc3986_userinfo_read(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval); -uriparser_uris_t *uriparser_parse_uri_ex(const char *uri_str, size_t uri_str_len, const uriparser_uris_t *uriparser_base_url, bool silent); +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); #endif diff --git a/ext/uri/uri_parser_whatwg.c b/ext/uri/uri_parser_whatwg.c index 66a11c3b4e9cd..9a7dccdb74146 100644 --- a/ext/uri/uri_parser_whatwg.c +++ b/ext/uri/uri_parser_whatwg.c @@ -25,10 +25,10 @@ #endif ZEND_TLS lxb_url_parser_t lexbor_parser; -ZEND_TLS unsigned short int lexbor_urls; +ZEND_TLS unsigned short int parsed_urls; -#define LEXBOR_MAX_URL_COUNT 500 -#define LEXBOR_MRAW_BYTE_SIZE 8192 +static const unsigned short int maximum_parses_before_cleanup = 500; +static const size_t lexbor_mraw_byte_size = 8192; static zend_always_inline void zval_string_or_null_to_lexbor_str(zval *value, lexbor_str_t *lexbor_str) { @@ -55,16 +55,6 @@ static zend_always_inline void zval_long_or_null_to_lexbor_str(zval *value, lexb } } -static void lexbor_cleanup_parser(void) -{ - if (++lexbor_urls % LEXBOR_MAX_URL_COUNT == 0) { - lexbor_mraw_clean(lexbor_parser.mraw); - lexbor_urls = 0; - } - - lxb_url_parser_clean(&lexbor_parser); -} - /** * Creates a Uri\WhatWg\UrlValidationError class by mapping error codes listed in * https://url.spec.whatwg.org/#writing to a Uri\WhatWg\UrlValidationErrorType enum. @@ -247,7 +237,7 @@ static void throw_invalid_url_exception_during_write(zval *errors, const char *c zend_update_property(exception->ce, exception, ZEND_STRL("errors"), errors); } -static lxb_status_t lexbor_serialize_callback(const lxb_char_t *data, size_t length, void *ctx) +static lxb_status_t serialize_to_smart_str_callback(const lxb_char_t *data, size_t length, void *ctx) { smart_str *uri_str = ctx; @@ -258,7 +248,7 @@ static lxb_status_t lexbor_serialize_callback(const lxb_char_t *data, size_t len return LXB_STATUS_OK; } -static zend_result lexbor_read_scheme(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +static zend_result php_uri_parser_whatwg_scheme_read(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { const lxb_url_t *lexbor_uri = internal_uri->uri; @@ -269,7 +259,7 @@ static zend_result lexbor_read_scheme(const struct uri_internal_t *internal_uri, return SUCCESS; } -static zend_result lexbor_write_scheme(struct uri_internal_t *internal_uri, zval *value, zval *errors) +static zend_result php_uri_parser_whatwg_scheme_write(struct uri_internal_t *internal_uri, zval *value, zval *errors) { lxb_url_t *lexbor_uri = internal_uri->uri; lexbor_str_t str = {0}; @@ -285,7 +275,7 @@ static zend_result lexbor_write_scheme(struct uri_internal_t *internal_uri, zval return SUCCESS; } -static zend_result lexbor_read_username(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +static zend_result php_uri_parser_whatwg_username_read(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { const lxb_url_t *lexbor_uri = internal_uri->uri; @@ -298,7 +288,7 @@ static zend_result lexbor_read_username(const struct uri_internal_t *internal_ur return SUCCESS; } -static zend_result lexbor_write_username(uri_internal_t *internal_uri, zval *value, zval *errors) +static zend_result php_uri_parser_whatwg_username_write(uri_internal_t *internal_uri, zval *value, zval *errors) { lxb_url_t *lexbor_uri = internal_uri->uri; lexbor_str_t str = {0}; @@ -314,7 +304,7 @@ static zend_result lexbor_write_username(uri_internal_t *internal_uri, zval *val return SUCCESS; } -static zend_result lexbor_read_password(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +static zend_result php_uri_parser_whatwg_password_read(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { const lxb_url_t *lexbor_uri = internal_uri->uri; @@ -327,7 +317,7 @@ static zend_result lexbor_read_password(const struct uri_internal_t *internal_ur return SUCCESS; } -static zend_result lexbor_write_password(struct uri_internal_t *internal_uri, zval *value, zval *errors) +static zend_result php_uri_parser_whatwg_password_write(struct uri_internal_t *internal_uri, zval *value, zval *errors) { lxb_url_t *lexbor_uri = internal_uri->uri; lexbor_str_t str = {0}; @@ -354,21 +344,21 @@ static zend_result init_idna(void) return lxb_unicode_idna_init(lexbor_parser.idna) == LXB_STATUS_OK ? SUCCESS : FAILURE; } -static zend_result lexbor_read_host(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +static zend_result php_uri_parser_whatwg_host_read(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { const lxb_url_t *lexbor_uri = internal_uri->uri; if (lexbor_uri->host.type == LXB_URL_HOST_TYPE_IPV4) { smart_str host_str = {0}; - lxb_url_serialize_host_ipv4(lexbor_uri->host.u.ipv4, lexbor_serialize_callback, &host_str); + lxb_url_serialize_host_ipv4(lexbor_uri->host.u.ipv4, serialize_to_smart_str_callback, &host_str); ZVAL_NEW_STR(retval, smart_str_extract(&host_str)); } else if (lexbor_uri->host.type == LXB_URL_HOST_TYPE_IPV6) { smart_str host_str = {0}; smart_str_appendc(&host_str, '['); - lxb_url_serialize_host_ipv6(lexbor_uri->host.u.ipv6, lexbor_serialize_callback, &host_str); + lxb_url_serialize_host_ipv6(lexbor_uri->host.u.ipv6, serialize_to_smart_str_callback, &host_str); smart_str_appendc(&host_str, ']'); ZVAL_NEW_STR(retval, smart_str_extract(&host_str)); @@ -381,7 +371,7 @@ static zend_result lexbor_read_host(const struct uri_internal_t *internal_uri, u if (init_idna() == FAILURE) { return FAILURE; } - lxb_url_serialize_host_unicode(lexbor_parser.idna, &lexbor_uri->host, lexbor_serialize_callback, &host_str); + lxb_url_serialize_host_unicode(lexbor_parser.idna, &lexbor_uri->host, serialize_to_smart_str_callback, &host_str); lxb_unicode_idna_clean(lexbor_parser.idna); ZVAL_NEW_STR(retval, smart_str_extract(&host_str)); @@ -401,7 +391,7 @@ static zend_result lexbor_read_host(const struct uri_internal_t *internal_uri, u return SUCCESS; } -static zend_result lexbor_write_host(struct uri_internal_t *internal_uri, zval *value, zval *errors) +static zend_result php_uri_parser_whatwg_host_write(struct uri_internal_t *internal_uri, zval *value, zval *errors) { lxb_url_t *lexbor_uri = internal_uri->uri; lexbor_str_t str = {0}; @@ -417,7 +407,7 @@ static zend_result lexbor_write_host(struct uri_internal_t *internal_uri, zval * return SUCCESS; } -static zend_result lexbor_read_port(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +static zend_result php_uri_parser_whatwg_port_read(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { const lxb_url_t *lexbor_uri = internal_uri->uri; @@ -430,7 +420,7 @@ static zend_result lexbor_read_port(const struct uri_internal_t *internal_uri, u return SUCCESS; } -static zend_result lexbor_write_port(struct uri_internal_t *internal_uri, zval *value, zval *errors) +static zend_result php_uri_parser_whatwg_port_write(struct uri_internal_t *internal_uri, zval *value, zval *errors) { lxb_url_t *lexbor_uri = internal_uri->uri; lexbor_str_t str = {0}; @@ -446,7 +436,7 @@ static zend_result lexbor_write_port(struct uri_internal_t *internal_uri, zval * return SUCCESS; } -static zend_result lexbor_read_path(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +static zend_result php_uri_parser_whatwg_path_read(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { const lxb_url_t *lexbor_uri = internal_uri->uri; @@ -459,7 +449,7 @@ static zend_result lexbor_read_path(const struct uri_internal_t *internal_uri, u return SUCCESS; } -static zend_result lexbor_write_path(struct uri_internal_t *internal_uri, zval *value, zval *errors) +static zend_result php_uri_parser_whatwg_path_write(struct uri_internal_t *internal_uri, zval *value, zval *errors) { lxb_url_t *lexbor_uri = internal_uri->uri; lexbor_str_t str = {0}; @@ -475,7 +465,7 @@ static zend_result lexbor_write_path(struct uri_internal_t *internal_uri, zval * return SUCCESS; } -static zend_result lexbor_read_query(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +static zend_result php_uri_parser_whatwg_query_read(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { const lxb_url_t *lexbor_uri = internal_uri->uri; @@ -488,7 +478,7 @@ static zend_result lexbor_read_query(const struct uri_internal_t *internal_uri, return SUCCESS; } -static zend_result lexbor_write_query(struct uri_internal_t *internal_uri, zval *value, zval *errors) +static zend_result php_uri_parser_whatwg_query_write(struct uri_internal_t *internal_uri, zval *value, zval *errors) { lxb_url_t *lexbor_uri = internal_uri->uri; lexbor_str_t str = {0}; @@ -504,7 +494,7 @@ static zend_result lexbor_write_query(struct uri_internal_t *internal_uri, zval return SUCCESS; } -static zend_result lexbor_read_fragment(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +static zend_result php_uri_parser_whatwg_fragment_read(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) { const lxb_url_t *lexbor_uri = internal_uri->uri; @@ -517,7 +507,7 @@ static zend_result lexbor_read_fragment(const struct uri_internal_t *internal_ur return SUCCESS; } -static zend_result lexbor_write_fragment(struct uri_internal_t *internal_uri, zval *value, zval *errors) +static zend_result php_uri_parser_whatwg_fragment_write(struct uri_internal_t *internal_uri, zval *value, zval *errors) { lxb_url_t *lexbor_uri = internal_uri->uri; lexbor_str_t str = {0}; @@ -536,7 +526,7 @@ static zend_result lexbor_write_fragment(struct uri_internal_t *internal_uri, zv PHP_RINIT_FUNCTION(uri_parser_whatwg) { lexbor_mraw_t *mraw = lexbor_mraw_create(); - lxb_status_t status = lexbor_mraw_init(mraw, LEXBOR_MRAW_BYTE_SIZE); + lxb_status_t status = lexbor_mraw_init(mraw, lexbor_mraw_byte_size); if (status != LXB_STATUS_OK) { lexbor_mraw_destroy(mraw, true); return FAILURE; @@ -549,7 +539,7 @@ PHP_RINIT_FUNCTION(uri_parser_whatwg) return FAILURE; } - lexbor_urls = 0; + parsed_urls = 0; return SUCCESS; } @@ -559,14 +549,24 @@ PHP_RSHUTDOWN_FUNCTION(uri_parser_whatwg) lxb_url_parser_memory_destroy(&lexbor_parser); lxb_url_parser_destroy(&lexbor_parser, false); - lexbor_urls = 0; + parsed_urls = 0; return SUCCESS; } -lxb_url_t *lexbor_parse_uri_ex(const char *uri_str, size_t uri_str_len, const lxb_url_t *lexbor_base_url, zval *errors, bool silent) +static void reset_parser_state(void) +{ + if (++parsed_urls % maximum_parses_before_cleanup == 0) { + lexbor_mraw_clean(lexbor_parser.mraw); + parsed_urls = 0; + } + + lxb_url_parser_clean(&lexbor_parser); +} + +lxb_url_t *php_uri_parser_whatwg_parse_ex(const char *uri_str, size_t uri_str_len, const lxb_url_t *lexbor_base_url, zval *errors, bool silent) { - lexbor_cleanup_parser(); + reset_parser_state(); lxb_url_t *url = lxb_url_parse(&lexbor_parser, lexbor_base_url, (unsigned char *) uri_str, uri_str_len); const char *reason = fill_errors(errors); @@ -579,19 +579,19 @@ lxb_url_t *lexbor_parse_uri_ex(const char *uri_str, size_t uri_str_len, const lx return url; } -static void *lexbor_parse_uri(const char *uri_str, size_t uri_str_len, const void *base_url, zval *errors, bool silent) +static void *php_uri_parser_whatwg_parse(const char *uri_str, size_t uri_str_len, const void *base_url, zval *errors, bool silent) { - return lexbor_parse_uri_ex(uri_str, uri_str_len, base_url, errors, silent); + return php_uri_parser_whatwg_parse_ex(uri_str, uri_str_len, base_url, errors, silent); } -static void *lexbor_clone_uri(void *uri) +static void *php_uri_parser_whatwg_clone(void *uri) { const lxb_url_t *lexbor_uri = uri; return lxb_url_clone(lexbor_parser.mraw, lexbor_uri); } -static zend_string *lexbor_uri_to_string(void *uri, uri_recomposition_mode_t recomposition_mode, bool exclude_fragment) +static zend_string *php_uri_parser_whatwg_to_string(void *uri, uri_recomposition_mode_t recomposition_mode, bool exclude_fragment) { const lxb_url_t *lexbor_uri = uri; smart_str uri_str = {0}; @@ -603,13 +603,13 @@ static zend_string *lexbor_uri_to_string(void *uri, uri_recomposition_mode_t rec if (init_idna() == FAILURE) { return NULL; } - lxb_url_serialize_idna(lexbor_parser.idna, lexbor_uri, lexbor_serialize_callback, &uri_str, exclude_fragment); + lxb_url_serialize_idna(lexbor_parser.idna, lexbor_uri, serialize_to_smart_str_callback, &uri_str, exclude_fragment); lxb_unicode_idna_clean(lexbor_parser.idna); break; case URI_RECOMPOSITION_RAW_ASCII: ZEND_FALLTHROUGH; case URI_RECOMPOSITION_NORMALIZED_ASCII: - lxb_url_serialize(lexbor_uri, lexbor_serialize_callback, &uri_str, exclude_fragment); + lxb_url_serialize(lexbor_uri, serialize_to_smart_str_callback, &uri_str, exclude_fragment); break; EMPTY_SWITCH_DEFAULT_CASE() } @@ -617,24 +617,24 @@ static zend_string *lexbor_uri_to_string(void *uri, uri_recomposition_mode_t rec return smart_str_extract(&uri_str); } -static void lexbor_free_uri(void *uri) +static void php_uri_parser_whatwg_free(void *uri) { } -const uri_parser_t lexbor_uri_parser = { - .name = URI_PARSER_WHATWG, - .parse_uri = lexbor_parse_uri, - .clone_uri = lexbor_clone_uri, - .uri_to_string = lexbor_uri_to_string, - .free_uri = lexbor_free_uri, +const uri_parser_t php_uri_parser_whatwg = { + .name = PHP_URI_PARSER_WHATWG, + .parse_uri = php_uri_parser_whatwg_parse, + .clone_uri = php_uri_parser_whatwg_clone, + .uri_to_string = php_uri_parser_whatwg_to_string, + .free_uri = php_uri_parser_whatwg_free, { - .scheme = {.read_func = lexbor_read_scheme, .write_func = lexbor_write_scheme}, - .username = {.read_func = lexbor_read_username, .write_func = lexbor_write_username}, - .password = {.read_func = lexbor_read_password, .write_func = lexbor_write_password}, - .host = {.read_func = lexbor_read_host, .write_func = lexbor_write_host}, - .port = {.read_func = lexbor_read_port, .write_func = lexbor_write_port}, - .path = {.read_func = lexbor_read_path, .write_func = lexbor_write_path}, - .query = {.read_func = lexbor_read_query, .write_func = lexbor_write_query}, - .fragment = {.read_func = lexbor_read_fragment, .write_func = lexbor_write_fragment}, + .scheme = {.read_func = php_uri_parser_whatwg_scheme_read, .write_func = php_uri_parser_whatwg_scheme_write}, + .username = {.read_func = php_uri_parser_whatwg_username_read, .write_func = php_uri_parser_whatwg_username_write}, + .password = {.read_func = php_uri_parser_whatwg_password_read, .write_func = php_uri_parser_whatwg_password_write}, + .host = {.read_func = php_uri_parser_whatwg_host_read, .write_func = php_uri_parser_whatwg_host_write}, + .port = {.read_func = php_uri_parser_whatwg_port_read, .write_func = php_uri_parser_whatwg_port_write}, + .path = {.read_func = php_uri_parser_whatwg_path_read, .write_func = php_uri_parser_whatwg_path_write}, + .query = {.read_func = php_uri_parser_whatwg_query_read, .write_func = php_uri_parser_whatwg_query_write}, + .fragment = {.read_func = php_uri_parser_whatwg_fragment_read, .write_func = php_uri_parser_whatwg_fragment_write}, } }; diff --git a/ext/uri/uri_parser_whatwg.h b/ext/uri/uri_parser_whatwg.h index c52998a725ba3..c05d4f7d5de14 100644 --- a/ext/uri/uri_parser_whatwg.h +++ b/ext/uri/uri_parser_whatwg.h @@ -20,9 +20,9 @@ #include "php_uri_common.h" #include "lexbor/url/url.h" -extern const uri_parser_t lexbor_uri_parser; +extern const uri_parser_t php_uri_parser_whatwg; -lxb_url_t *lexbor_parse_uri_ex(const char *uri_str, size_t uri_str_len, const lxb_url_t *lexbor_base_url, zval *errors, bool silent); +lxb_url_t *php_uri_parser_whatwg_parse_ex(const char *uri_str, size_t uri_str_len, const lxb_url_t *lexbor_base_url, zval *errors, bool silent); PHP_RINIT_FUNCTION(uri_parser_whatwg); PHP_RSHUTDOWN_FUNCTION(uri_parser_whatwg);