Skip to content

Commit 84fc2df

Browse files
committed
Implement class constant pattern
1 parent e659715 commit 84fc2df

File tree

5 files changed

+86
-3
lines changed

5 files changed

+86
-3
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
--TEST--
2+
Class constant pattern
3+
--FILE--
4+
<?php
5+
6+
class Foo {
7+
const A = 'a';
8+
private const B = 'b';
9+
10+
public static function test() {
11+
var_dump('b' is self::B);
12+
var_dump('c' is self::B);
13+
}
14+
}
15+
enum Bar {
16+
case A;
17+
}
18+
19+
var_dump('a' is Foo::A);
20+
var_dump('b' is Foo::A);
21+
try {
22+
var_dump('a' is Foo::B);
23+
} catch (Error $e) {
24+
echo $e->getMessage(), "\n";
25+
}
26+
try {
27+
var_dump('a' is Foo::C);
28+
} catch (Error $e) {
29+
echo $e->getMessage(), "\n";
30+
}
31+
Foo::test();
32+
var_dump(Bar::A is Bar::A);
33+
var_dump('foo' is Bar::A);
34+
35+
?>
36+
--EXPECT--
37+
bool(true)
38+
bool(false)
39+
Cannot access private constant Foo::B
40+
Undefined constant Foo::C
41+
bool(true)
42+
bool(false)
43+
bool(true)
44+
bool(false)

Zend/zend_ast.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ enum _zend_ast_kind {
162162
ZEND_AST_RANGE_PATTERN,
163163
ZEND_AST_ARRAY_PATTERN_ELEMENT,
164164
ZEND_AST_BINDING_PATTERN,
165+
ZEND_AST_CLASS_CONST_PATTERN,
165166

166167
/* 3 child nodes */
167168
ZEND_AST_METHOD_CALL = 3 << ZEND_AST_NUM_CHILDREN_SHIFT,

Zend/zend_compile.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6086,9 +6086,8 @@ static void zend_compile_match(znode *result, zend_ast *ast)
60866086
efree(jmp_end_opnums);
60876087
}
60886088

6089-
static void zend_compile_object_pattern(zend_ast **ast_ptr)
6089+
static void zend_compile_pattern_class_name(zend_ast *ast)
60906090
{
6091-
zend_ast *ast = *ast_ptr;
60926091
zend_ast *class_name_ast = ast->child[0];
60936092
ZEND_ASSERT(class_name_ast->kind == ZEND_AST_ZVAL);
60946093

@@ -6118,6 +6117,12 @@ static void zend_compile_object_pattern(zend_ast **ast_ptr)
61186117
}
61196118
}
61206119

6120+
static void zend_compile_object_pattern(zend_ast **ast_ptr)
6121+
{
6122+
zend_ast *ast = *ast_ptr;
6123+
zend_compile_pattern_class_name(ast);
6124+
}
6125+
61216126
static zend_type zend_compile_single_typename(zend_ast *ast);
61226127

61236128
static void zend_compile_type_pattern(zend_ast **ast_ptr)
@@ -6144,6 +6149,13 @@ static void zend_compile_type_pattern(zend_ast **ast_ptr)
61446149
}
61456150
}
61466151

6152+
static void zend_compile_class_const_pattern(zend_ast **ast_ptr)
6153+
{
6154+
// zend_ast *ast = *ast_ptr;
6155+
// FIXME: Compiling the class name breaks zend_get_class_constant_ex.
6156+
// zend_compile_pattern_class_name(ast);
6157+
}
6158+
61476159
static void zend_compile_binding_pattern(zend_ast **ast_ptr)
61486160
{
61496161
zend_ast *binding_pattern_ast = *ast_ptr;
@@ -6204,6 +6216,9 @@ static void zend_compile_pattern(zend_ast **ast_ptr, void *context)
62046216
case ZEND_AST_ARRAY_PATTERN:
62056217
zend_compile_array_pattern(ast_ptr);
62066218
break;
6219+
case ZEND_AST_CLASS_CONST_PATTERN:
6220+
zend_compile_class_const_pattern(ast_ptr);
6221+
break;
62076222
}
62086223

62096224
zend_ast_apply(ast, zend_compile_pattern, context);

Zend/zend_language_parser.y

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
284284
%type <ast> match match_arm_list non_empty_match_arm_list match_arm match_arm_cond_list match_arm_cond
285285
%type <ast> enum_declaration_statement enum_backing_type enum_case enum_case_expr
286286
%type <ast> function_name non_empty_member_modifiers
287-
%type <ast> pattern atomic_pattern compound_pattern type_pattern scalar_pattern or_pattern and_pattern
287+
%type <ast> pattern atomic_pattern compound_pattern type_pattern scalar_pattern or_pattern and_pattern class_const_pattern
288288
%type <ast> object_pattern object_pattern_element_list non_empty_object_pattern_element_list
289289
%type <ast> object_pattern_element range_pattern binding_pattern
290290
%type <ast> array_pattern array_pattern_element_list array_pattern_element
@@ -1291,6 +1291,7 @@ atomic_pattern:
12911291
| range_pattern { $$ = $1; }
12921292
| array_pattern { $$ = $1; }
12931293
| binding_pattern { $$ = $1; }
1294+
| class_const_pattern { $$ = $1; }
12941295
| T_UNDERSCORE { $$ = zend_ast_create(ZEND_AST_WILDCARD_PATTERN); }
12951296
| '(' pattern ')' { $$ = $2; }
12961297
;
@@ -1378,6 +1379,11 @@ array_pattern_element:
13781379
{ $$ = zend_ast_create(ZEND_AST_ARRAY_PATTERN_ELEMENT, $1, $3); }
13791380
;
13801381

1382+
class_const_pattern:
1383+
class_name T_PAAMAYIM_NEKUDOTAYIM identifier
1384+
{ $$ = zend_ast_create(ZEND_AST_CLASS_CONST_PATTERN, $1, $3); }
1385+
;
1386+
13811387
inline_function:
13821388
function returns_ref backup_doc_comment '(' parameter_list ')' lexical_vars return_type
13831389
backup_fn_flags '{' inner_statement_list '}' backup_fn_flags

Zend/zend_pattern_matching.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515
*/
1616

1717
#include "zend_pattern_matching.h"
18+
#include "zend_API.h"
1819
#include "zend_compile.h"
1920
#include "zend_execute.h"
2021
#include "zend_exceptions.h"
2122
#include "zend_type_info.h"
23+
#include "zend_constants.h"
2224

2325
typedef enum {
2426
PM_ERROR = -1,
@@ -228,6 +230,19 @@ static pm_result match_array(zval *zv, zend_ast *pattern)
228230
return PM_MATCH;
229231
}
230232

233+
pm_result match_class_const(zval *zv, zend_ast *pattern)
234+
{
235+
zend_string *class_name = !pattern->attr
236+
? zend_ast_get_str(pattern->child[0])
237+
: NULL;
238+
zend_string *constant_name = zend_ast_get_str(pattern->child[1]);
239+
zval *constant_zv = zend_get_class_constant_ex(class_name, constant_name, zend_get_executed_scope(), pattern->attr);
240+
if (EG(exception)) {
241+
return PM_ERROR;
242+
}
243+
return zend_is_identical(zv, constant_zv) ? PM_MATCH : PM_MISMATCH;
244+
}
245+
231246
pm_result zend_pattern_match_ex(zval *zv, zend_ast *pattern)
232247
{
233248
ZVAL_DEREF(zv);
@@ -262,6 +277,8 @@ pm_result zend_pattern_match_ex(zval *zv, zend_ast *pattern)
262277
return match_binding(zv, pattern);
263278
case ZEND_AST_ARRAY_PATTERN:
264279
return match_array(zv, pattern);
280+
case ZEND_AST_CLASS_CONST_PATTERN:
281+
return match_class_const(zv, pattern);
265282
EMPTY_SWITCH_DEFAULT_CASE();
266283
}
267284
}

0 commit comments

Comments
 (0)