Skip to content

Commit 4dcde9c

Browse files
committed
Don't evalutae ZEND_AST_CLASS_CONST to ZEND_AST_CONSTANT ar
compile-time. Keep at to run-time and use Fast Class Cache during run-time evaluation.
1 parent 718dd06 commit 4dcde9c

File tree

7 files changed

+124
-15
lines changed

7 files changed

+124
-15
lines changed

Zend/zend_ast.c

+13
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,19 @@ ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast
784784
zend_enum_new(result, ce, case_name, case_value_zv);
785785
break;
786786
}
787+
case ZEND_AST_CLASS_CONST:
788+
{
789+
zend_string *class_name = zend_ast_get_str(ast->child[0]);
790+
zend_string *const_name = zend_ast_get_str(ast->child[1]);
791+
zval *zv = zend_get_class_constant_ex(class_name, const_name, scope, ast->attr);
792+
793+
if (UNEXPECTED(zv == NULL)) {
794+
ZVAL_UNDEF(result);
795+
return FAILURE;
796+
}
797+
ZVAL_COPY_OR_DUP(result, zv);
798+
break;
799+
}
787800
default:
788801
zend_throw_error(NULL, "Unsupported constant expression");
789802
ret = FAILURE;

Zend/zend_compile.c

+8-11
Original file line numberDiff line numberDiff line change
@@ -9462,10 +9462,7 @@ void zend_compile_const_expr_class_const(zend_ast **ast_ptr) /* {{{ */
94629462
{
94639463
zend_ast *ast = *ast_ptr;
94649464
zend_ast *class_ast = ast->child[0];
9465-
zend_ast *const_ast = ast->child[1];
94669465
zend_string *class_name;
9467-
zend_string *const_name = zend_ast_get_str(const_ast);
9468-
zend_string *name;
94699466
int fetch_type;
94709467

94719468
if (class_ast->kind != ZEND_AST_ZVAL) {
@@ -9482,17 +9479,17 @@ void zend_compile_const_expr_class_const(zend_ast **ast_ptr) /* {{{ */
94829479
}
94839480

94849481
if (ZEND_FETCH_CLASS_DEFAULT == fetch_type) {
9485-
class_name = zend_resolve_class_name_ast(class_ast);
9486-
} else {
9487-
zend_string_addref(class_name);
9488-
}
9482+
zend_string *tmp = zend_resolve_class_name_ast(class_ast);
94899483

9490-
name = zend_create_member_string(class_name, const_name);
9484+
zend_string_release_ex(class_name, 0);
9485+
if (tmp != class_name) {
9486+
zval *zv = zend_ast_get_zval(class_ast);
94919487

9492-
zend_ast_destroy(ast);
9493-
zend_string_release_ex(class_name, 0);
9488+
ZVAL_STR(zv, tmp);
9489+
}
9490+
}
94949491

9495-
*ast_ptr = zend_ast_create_constant(name, fetch_type | ZEND_FETCH_CLASS_EXCEPTION);
9492+
ast->attr |= ZEND_FETCH_CLASS_EXCEPTION;
94969493
}
94979494
/* }}} */
94989495

Zend/zend_constants.c

+86-2
Original file line numberDiff line numberDiff line change
@@ -324,11 +324,87 @@ ZEND_API zval *zend_get_constant(zend_string *name)
324324
return NULL;
325325
}
326326

327+
ZEND_API zval *zend_get_class_constant_ex(zend_string *class_name, zend_string *constant_name, zend_class_entry *scope, uint32_t flags)
328+
{
329+
zend_class_entry *ce = NULL;
330+
zend_class_constant *c = NULL;
331+
zval *ret_constant = NULL;
332+
333+
if (ZSTR_HAS_CE_CACHE(class_name)) {
334+
ce = ZSTR_GET_CE_CACHE(class_name);
335+
if (!ce) {
336+
ce = zend_fetch_class(class_name, flags);
337+
}
338+
} else if (zend_string_equals_literal_ci(class_name, "self")) {
339+
if (UNEXPECTED(!scope)) {
340+
zend_throw_error(NULL, "Cannot access \"self\" when no class scope is active");
341+
goto failure;
342+
}
343+
ce = scope;
344+
} else if (zend_string_equals_literal_ci(class_name, "parent")) {
345+
if (UNEXPECTED(!scope)) {
346+
zend_throw_error(NULL, "Cannot access \"parent\" when no class scope is active");
347+
goto failure;
348+
} else if (UNEXPECTED(!scope->parent)) {
349+
zend_throw_error(NULL, "Cannot access \"parent\" when current class scope has no parent");
350+
goto failure;
351+
} else {
352+
ce = scope->parent;
353+
}
354+
} else if (zend_string_equals_literal_ci(class_name, "static")) {
355+
ce = zend_get_called_scope(EG(current_execute_data));
356+
if (UNEXPECTED(!ce)) {
357+
zend_throw_error(NULL, "Cannot access \"static\" when no class scope is active");
358+
goto failure;
359+
}
360+
} else {
361+
ce = zend_fetch_class(class_name, flags);
362+
}
363+
if (ce) {
364+
c = zend_hash_find_ptr(CE_CONSTANTS_TABLE(ce), constant_name);
365+
if (c == NULL) {
366+
if ((flags & ZEND_FETCH_CLASS_SILENT) == 0) {
367+
zend_throw_error(NULL, "Undefined constant %s::%s", ZSTR_VAL(class_name), ZSTR_VAL(constant_name));
368+
goto failure;
369+
}
370+
ret_constant = NULL;
371+
} else {
372+
if (!zend_verify_const_access(c, scope)) {
373+
if ((flags & ZEND_FETCH_CLASS_SILENT) == 0) {
374+
zend_throw_error(NULL, "Cannot access %s constant %s::%s", zend_visibility_string(Z_ACCESS_FLAGS(c->value)), ZSTR_VAL(class_name), ZSTR_VAL(constant_name));
375+
}
376+
goto failure;
377+
}
378+
ret_constant = &c->value;
379+
}
380+
}
381+
382+
if (ret_constant && Z_TYPE_P(ret_constant) == IS_CONSTANT_AST) {
383+
zend_result ret;
384+
385+
if (IS_CONSTANT_VISITED(ret_constant)) {
386+
zend_throw_error(NULL, "Cannot declare self-referencing constant %s::%s", ZSTR_VAL(class_name), ZSTR_VAL(constant_name));
387+
ret_constant = NULL;
388+
goto failure;
389+
}
390+
391+
MARK_CONSTANT_VISITED(ret_constant);
392+
ret = zval_update_constant_ex(ret_constant, c->ce);
393+
RESET_CONSTANT_VISITED(ret_constant);
394+
395+
if (UNEXPECTED(ret != SUCCESS)) {
396+
ret_constant = NULL;
397+
goto failure;
398+
}
399+
}
400+
failure:
401+
return ret_constant;
402+
}
403+
327404
ZEND_API zval *zend_get_constant_ex(zend_string *cname, zend_class_entry *scope, uint32_t flags)
328405
{
329406
zend_constant *c;
330407
const char *colon;
331-
zend_class_entry *ce = NULL;
332408
const char *name = ZSTR_VAL(cname);
333409
size_t name_len = ZSTR_LEN(cname);
334410

@@ -344,7 +420,14 @@ ZEND_API zval *zend_get_constant_ex(zend_string *cname, zend_class_entry *scope,
344420
int class_name_len = colon - name - 1;
345421
size_t const_name_len = name_len - class_name_len - 2;
346422
zend_string *constant_name = zend_string_init(colon + 1, const_name_len, 0);
347-
zend_string *class_name = zend_string_init(name, class_name_len, 0);
423+
zend_string *class_name = zend_string_init_interned(name, class_name_len, 0);
424+
zval *ret_constant = zend_get_class_constant_ex(class_name, constant_name, scope, flags);
425+
426+
zend_string_release_ex(class_name, 0);
427+
zend_string_efree(constant_name);
428+
return ret_constant;
429+
/*
430+
zend_class_entry *ce = NULL;
348431
zend_class_constant *c = NULL;
349432
zval *ret_constant = NULL;
350433
@@ -414,6 +497,7 @@ ZEND_API zval *zend_get_constant_ex(zend_string *cname, zend_class_entry *scope,
414497
zend_string_release_ex(class_name, 0);
415498
zend_string_efree(constant_name);
416499
return ret_constant;
500+
*/
417501
}
418502

419503
/* non-class constant */

Zend/zend_constants.h

+1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ ZEND_API bool zend_verify_const_access(zend_class_constant *c, zend_class_entry
7676
ZEND_API zval *zend_get_constant(zend_string *name);
7777
ZEND_API zval *zend_get_constant_str(const char *name, size_t name_len);
7878
ZEND_API zval *zend_get_constant_ex(zend_string *name, zend_class_entry *scope, uint32_t flags);
79+
ZEND_API zval *zend_get_class_constant_ex(zend_string *class_name, zend_string *constant_name, zend_class_entry *scope, uint32_t flags);
7980
ZEND_API void zend_register_bool_constant(const char *name, size_t name_len, bool bval, int flags, int module_number);
8081
ZEND_API void zend_register_null_constant(const char *name, size_t name_len, int flags, int module_number);
8182
ZEND_API void zend_register_long_constant(const char *name, size_t name_len, zend_long lval, int flags, int module_number);

Zend/zend_inheritance.c

+4
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,10 @@ static ZEND_COLD zend_string *zend_get_function_declaration(
786786
zend_ast *ast = Z_ASTVAL_P(zv);
787787
if (ast->kind == ZEND_AST_CONSTANT) {
788788
smart_str_append(&str, zend_ast_get_constant_name(ast));
789+
} else if (ast->kind == ZEND_AST_CLASS_CONST) {
790+
smart_str_append(&str, zend_ast_get_str(ast->child[0]));
791+
smart_str_appends(&str, "::");
792+
smart_str_append(&str, zend_ast_get_str(ast->child[1]));
789793
} else {
790794
smart_str_appends(&str, "<expression>");
791795
}

ext/reflection/php_reflection.c

+10-1
Original file line numberDiff line numberDiff line change
@@ -2820,7 +2820,9 @@ ZEND_METHOD(ReflectionParameter, isDefaultValueConstant)
28202820

28212821
if (Z_TYPE(default_value) == IS_CONSTANT_AST) {
28222822
zend_ast *ast = Z_ASTVAL(default_value);
2823-
RETVAL_BOOL(ast->kind == ZEND_AST_CONSTANT || ast->kind == ZEND_AST_CONSTANT_CLASS);
2823+
RETVAL_BOOL(ast->kind == ZEND_AST_CONSTANT
2824+
|| ast->kind == ZEND_AST_CONSTANT_CLASS
2825+
|| ast->kind == ZEND_AST_CLASS_CONST);
28242826
} else {
28252827
RETVAL_FALSE;
28262828
}
@@ -2858,6 +2860,13 @@ ZEND_METHOD(ReflectionParameter, getDefaultValueConstantName)
28582860
RETVAL_STR_COPY(zend_ast_get_constant_name(ast));
28592861
} else if (ast->kind == ZEND_AST_CONSTANT_CLASS) {
28602862
RETVAL_STRINGL("__CLASS__", sizeof("__CLASS__")-1);
2863+
} else if (ast->kind == ZEND_AST_CLASS_CONST) {
2864+
zend_string *class_name = zend_ast_get_str(ast->child[0]);
2865+
zend_string *const_name = zend_ast_get_str(ast->child[1]);
2866+
RETVAL_NEW_STR(zend_string_concat3(
2867+
ZSTR_VAL(class_name), ZSTR_LEN(class_name),
2868+
"::", sizeof("::")-1,
2869+
ZSTR_VAL(const_name), ZSTR_LEN(const_name)));
28612870
} else {
28622871
RETVAL_NULL();
28632872
}

sapi/phpdbg/phpdbg_utils.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -844,7 +844,8 @@ char *phpdbg_short_zval_print(zval *zv, int maxlen) /* {{{ */
844844
zend_ast *ast = Z_ASTVAL_P(zv);
845845

846846
if (ast->kind == ZEND_AST_CONSTANT
847-
|| ast->kind == ZEND_AST_CONSTANT_CLASS) {
847+
|| ast->kind == ZEND_AST_CONSTANT_CLASS
848+
|| ast->kind == ZEND_AST_CLASS_CONST) {
848849
decode = estrdup("<constant>");
849850
} else {
850851
decode = estrdup("<ast>");

0 commit comments

Comments
 (0)