Skip to content

Commit 7b78bf1

Browse files
committed
Normalize ('\bar')() by removing leading backslash
1 parent 6ba2117 commit 7b78bf1

File tree

3 files changed

+77
-0
lines changed

3 files changed

+77
-0
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,9 @@ Version changelog
417417
### 40 (in development)
418418

419419
* `AST_COALESCE` is now represented as an `AST_BINARY_OP` with flag `BINARY_COALESCE`.
420+
* For `AST_NAME` nodes with `NAME_FQ` the leading backslash is now dropped if syntax like
421+
`('\bar')()` is used. Previously this would return the name as `'\bar'`, while a normal `\bar()`
422+
call would return it as `'bar'`. Now always the latter form is used.
420423

421424
### 30 (current)
422425

ast.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,18 @@ static void ast_fill_children_ht(HashTable *ht, zend_ast *ast, zend_long version
218218
}
219219

220220
if (ast_is_name(child, ast, i)) {
221+
if (version >= 40 && child->attr == ZEND_NAME_FQ) {
222+
/* Ensure there is no leading \ for fully-qualified names. This can happen if
223+
* something like ('\bar')() is used. */
224+
zval *name = zend_ast_get_zval(child);
225+
if (Z_STRVAL_P(name)[0] == '\\') {
226+
zend_string *new_name = zend_string_init(
227+
Z_STRVAL_P(name) + 1, Z_STRLEN_P(name) - 1, 0);
228+
zend_string_release(Z_STR_P(name));
229+
Z_STR_P(name) = new_name;
230+
}
231+
}
232+
221233
ast_create_virtual_node(&child_zv, AST_NAME, child, version);
222234
} else if (ast->kind == ZEND_AST_CLOSURE_USES) {
223235
ast_create_virtual_node(&child_zv, AST_CLOSURE_VAR, child, version);

tests/name_node.phpt

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
--TEST--
2+
Name nodes
3+
--FILE--
4+
<?php
5+
6+
require __DIR__ . '/../util.php';
7+
8+
$code = <<<'PHP'
9+
<?php
10+
foo();
11+
\foo();
12+
('foo')();
13+
('\foo')();
14+
PHP;
15+
16+
echo ast_dump(ast\parse_code($code, $version=30)), "\n";
17+
echo ast_dump(ast\parse_code($code, $version=40)), "\n";
18+
19+
?>
20+
--EXPECT--
21+
AST_STMT_LIST
22+
0: AST_CALL
23+
expr: AST_NAME
24+
flags: NAME_NOT_FQ (1)
25+
name: "foo"
26+
args: AST_ARG_LIST
27+
1: AST_CALL
28+
expr: AST_NAME
29+
flags: NAME_FQ (0)
30+
name: "foo"
31+
args: AST_ARG_LIST
32+
2: AST_CALL
33+
expr: AST_NAME
34+
flags: NAME_FQ (0)
35+
name: "foo"
36+
args: AST_ARG_LIST
37+
3: AST_CALL
38+
expr: AST_NAME
39+
flags: NAME_FQ (0)
40+
name: "\foo"
41+
args: AST_ARG_LIST
42+
AST_STMT_LIST
43+
0: AST_CALL
44+
expr: AST_NAME
45+
flags: NAME_NOT_FQ (1)
46+
name: "foo"
47+
args: AST_ARG_LIST
48+
1: AST_CALL
49+
expr: AST_NAME
50+
flags: NAME_FQ (0)
51+
name: "foo"
52+
args: AST_ARG_LIST
53+
2: AST_CALL
54+
expr: AST_NAME
55+
flags: NAME_FQ (0)
56+
name: "foo"
57+
args: AST_ARG_LIST
58+
3: AST_CALL
59+
expr: AST_NAME
60+
flags: NAME_FQ (0)
61+
name: "foo"
62+
args: AST_ARG_LIST

0 commit comments

Comments
 (0)