Skip to content

Commit 9ff3800

Browse files
committed
Improve and generalize class constant substitution
1 parent 8989354 commit 9ff3800

File tree

1 file changed

+85
-31
lines changed

1 file changed

+85
-31
lines changed

Zend/zend_compile.c

Lines changed: 85 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1155,6 +1155,13 @@ ZEND_API int zend_unmangle_property_name_ex(const zend_string *name, const char
11551155
}
11561156
/* }}} */
11571157

1158+
static inline zend_bool zend_string_equals_str_ci(zend_string *str1, zend_string *str2) /* {{{ */
1159+
{
1160+
return str1->len == str2->len
1161+
&& !zend_binary_strcasecmp(str1->val, str1->len, str2->val, str2->len);
1162+
}
1163+
/* }}} */
1164+
11581165
static zend_constant *zend_lookup_reserved_const(const char *name, size_t len) /* {{{ */
11591166
{
11601167
zend_constant *c = zend_hash_find_ptr_lc(EG(zend_constants), name, len);
@@ -1169,13 +1176,14 @@ static zend_bool zend_try_ct_eval_const(zval *zv, zend_string *name, zend_bool i
11691176
{
11701177
zend_constant *c;
11711178

1172-
if (!(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION)) {
1173-
/* Substitute case-sensitive (or lowercase) persistent constants */
1174-
c = zend_hash_find_ptr(EG(zend_constants), name);
1175-
if (c && (c->flags & CONST_PERSISTENT)) {
1176-
ZVAL_DUP(zv, &c->value);
1177-
return 1;
1178-
}
1179+
/* Substitute case-sensitive (or lowercase) constants */
1180+
c = zend_hash_find_ptr(EG(zend_constants), name);
1181+
if (c && (
1182+
(c->flags & CONST_PERSISTENT)
1183+
|| (Z_TYPE(c->value) < IS_CONSTANT && !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION)))
1184+
) {
1185+
ZVAL_DUP(zv, &c->value);
1186+
return 1;
11791187
}
11801188

11811189
{
@@ -1198,6 +1206,33 @@ static zend_bool zend_try_ct_eval_const(zval *zv, zend_string *name, zend_bool i
11981206
}
11991207
/* }}} */
12001208

1209+
static zend_bool zend_try_ct_eval_class_const(zval *zv, zend_string *class_name, zend_string *name) /* {{{ */
1210+
{
1211+
uint32_t fetch_type = zend_get_class_fetch_type(class_name);
1212+
zval *c;
1213+
1214+
if (CG(active_class_entry) && (fetch_type == ZEND_FETCH_CLASS_SELF || (fetch_type == ZEND_FETCH_CLASS_DEFAULT && zend_string_equals_str_ci(class_name, CG(active_class_entry)->name)))) {
1215+
c = zend_hash_find(&CG(active_class_entry)->constants_table, name);
1216+
} else if (fetch_type == ZEND_FETCH_CLASS_DEFAULT && !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION)) {
1217+
zend_class_entry *ce = zend_hash_find_ptr(CG(class_table), class_name);
1218+
if (ce) {
1219+
c = zend_hash_find(&ce->constants_table, name);
1220+
} else {
1221+
return 0;
1222+
}
1223+
} else {
1224+
return 0;
1225+
}
1226+
1227+
/* Substitute case-sensitive (or lowercase) persistent class constants */
1228+
if (c && Z_TYPE_P(c) < IS_CONSTANT) {
1229+
ZVAL_DUP(zv, c);
1230+
return 1;
1231+
}
1232+
1233+
return 0;
1234+
}
1235+
12011236
void zend_init_list(void *result, void *item) /* {{{ */
12021237
{
12031238
void** list = emalloc(sizeof(void*) * 2);
@@ -1627,13 +1662,6 @@ ZEND_API size_t zend_dirname(char *path, size_t len)
16271662
}
16281663
/* }}} */
16291664

1630-
static inline zend_bool zend_string_equals_str_ci(zend_string *str1, zend_string *str2) /* {{{ */
1631-
{
1632-
return str1->len == str2->len
1633-
&& !zend_binary_strcasecmp(str1->val, str1->len, str2->val, str2->len);
1634-
}
1635-
/* }}} */
1636-
16371665
static void zend_adjust_for_fetch_type(zend_op *opline, uint32_t type) /* {{{ */
16381666
{
16391667
switch (type & BP_VAR_MASK) {
@@ -5814,30 +5842,32 @@ void zend_compile_class_const(znode *result, zend_ast *ast) /* {{{ */
58145842

58155843
znode class_node, const_node;
58165844
zend_op *opline, *class_op = NULL;
5845+
zend_string *resolved_name;
5846+
5847+
zend_eval_const_expr(&class_ast);
5848+
zend_eval_const_expr(&const_ast);
5849+
5850+
if (class_ast->kind == ZEND_AST_ZVAL) {
5851+
resolved_name = zend_resolve_class_name_ast(class_ast);
5852+
if (const_ast->kind == ZEND_AST_ZVAL && zend_try_ct_eval_class_const(&result->u.constant, resolved_name, zend_ast_get_str(const_ast))) {
5853+
result->op_type = IS_CONST;
5854+
zend_string_release(resolved_name);
5855+
return;
5856+
}
5857+
}
58175858

58185859
if (zend_is_const_default_class_ref(class_ast)) {
58195860
class_node.op_type = IS_CONST;
5820-
ZVAL_STR(&class_node.u.constant, zend_resolve_class_name_ast(class_ast));
5861+
ZVAL_STR(&class_node.u.constant, resolved_name);
58215862
} else {
5863+
if (class_ast->kind == ZEND_AST_ZVAL) {
5864+
zend_string_release(resolved_name);
5865+
}
58225866
class_op = zend_compile_class_ref(&class_node, class_ast);
58235867
}
58245868

58255869
zend_compile_expr(&const_node, const_ast);
58265870

5827-
if (class_op && const_node.op_type == IS_CONST && class_op->extended_value == ZEND_FETCH_CLASS_SELF && Z_TYPE(const_node.u.constant) == IS_STRING && CG(active_class_entry)) {
5828-
zval *const_zv = zend_hash_find(&CG(active_class_entry)->constants_table, Z_STR(const_node.u.constant));
5829-
if (const_zv && Z_TYPE_P(const_zv) < IS_CONSTANT) {
5830-
CG(active_op_array)->last--;
5831-
CG(active_op_array)->T--;
5832-
5833-
result->op_type = IS_CONST;
5834-
ZVAL_COPY(&result->u.constant, const_zv);
5835-
5836-
zend_string_release(Z_STR(const_node.u.constant));
5837-
return;
5838-
}
5839-
}
5840-
58415871
opline = zend_emit_op_tmp(result, ZEND_FETCH_CONSTANT, NULL, &const_node);
58425872

58435873
zend_set_class_name_op1(opline, &class_node);
@@ -5877,8 +5907,8 @@ void zend_compile_resolve_class_name(znode *result, zend_ast *ast) /* {{{ */
58775907
ZVAL_STR_COPY(&result->u.constant, CG(active_class_entry)->name);
58785908
}
58795909
break;
5880-
case ZEND_FETCH_CLASS_STATIC:
5881-
case ZEND_FETCH_CLASS_PARENT:
5910+
case ZEND_FETCH_CLASS_STATIC:
5911+
case ZEND_FETCH_CLASS_PARENT:
58825912
if (!CG(active_class_entry)) {
58835913
zend_error_noreturn(E_COMPILE_ERROR,
58845914
"Cannot access %s::class when no class scope is active",
@@ -6555,6 +6585,30 @@ void zend_eval_const_expr(zend_ast **ast_ptr) /* {{{ */
65556585
zend_string_release(resolved_name);
65566586
break;
65576587
}
6588+
case ZEND_AST_CLASS_CONST:
6589+
{
6590+
zend_ast *class_ast = ast->child[0];
6591+
zend_ast *name_ast = ast->child[1];
6592+
zend_string *resolved_name;
6593+
6594+
zend_eval_const_expr(&class_ast);
6595+
zend_eval_const_expr(&name_ast);
6596+
6597+
if (class_ast->kind != ZEND_AST_ZVAL || name_ast->kind != ZEND_AST_ZVAL) {
6598+
return;
6599+
}
6600+
6601+
resolved_name = zend_resolve_class_name_ast(class_ast);
6602+
6603+
if (!zend_try_ct_eval_class_const(&result, resolved_name, zend_ast_get_str(name_ast))) {
6604+
zend_string_release(resolved_name);
6605+
return;
6606+
}
6607+
6608+
zend_string_release(resolved_name);
6609+
break;
6610+
}
6611+
65586612
default:
65596613
return;
65606614
}

0 commit comments

Comments
 (0)