From: Bob Weinand Date: Tue, 10 Feb 2015 14:43:23 +0000 (+0100) Subject: Revert "Revert "Improve and generalize class constant substitution"" X-Git-Tag: PRE_PHP7_EREG_MYSQL_REMOVALS~199 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=830d3d79b3744db021f2183857c5a625e96c6315;p=php Revert "Revert "Improve and generalize class constant substitution"" This reverts commit 400e65e955f08ad6ae57c1a15be04d5852107252. Removing ReflectionParameter::getDefaultValueConstantName() and isDefaultValueConstant() They become useless with such optimizations and already anyway are (e.g. CONSTANT?:CONSTANT ... yields the constant back without telling isDefaultValueConstant() about it etc.) --- diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index bdd0c17583..60d8472677 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1155,6 +1155,13 @@ ZEND_API int zend_unmangle_property_name_ex(const zend_string *name, const char } /* }}} */ +static inline zend_bool zend_string_equals_str_ci(zend_string *str1, zend_string *str2) /* {{{ */ +{ + return str1->len == str2->len + && !zend_binary_strcasecmp(str1->val, str1->len, str2->val, str2->len); +} +/* }}} */ + static zend_constant *zend_lookup_reserved_const(const char *name, size_t len) /* {{{ */ { 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 { zend_constant *c; - if (!(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION)) { - /* Substitute case-sensitive (or lowercase) persistent constants */ - c = zend_hash_find_ptr(EG(zend_constants), name); - if (c && (c->flags & CONST_PERSISTENT)) { - ZVAL_DUP(zv, &c->value); - return 1; - } + /* Substitute case-sensitive (or lowercase) constants */ + c = zend_hash_find_ptr(EG(zend_constants), name); + if (c && ( + (c->flags & CONST_PERSISTENT) + || (Z_TYPE(c->value) < IS_OBJECT && !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION))) + ) { + ZVAL_DUP(zv, &c->value); + return 1; } { @@ -1198,6 +1206,33 @@ static zend_bool zend_try_ct_eval_const(zval *zv, zend_string *name, zend_bool i } /* }}} */ +static zend_bool zend_try_ct_eval_class_const(zval *zv, zend_string *class_name, zend_string *name) /* {{{ */ +{ + uint32_t fetch_type = zend_get_class_fetch_type(class_name); + zval *c; + + 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)))) { + c = zend_hash_find(&CG(active_class_entry)->constants_table, name); + } else if (fetch_type == ZEND_FETCH_CLASS_DEFAULT && !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION)) { + zend_class_entry *ce = zend_hash_find_ptr_lc(CG(class_table), class_name->val, class_name->len); + if (ce) { + c = zend_hash_find(&ce->constants_table, name); + } else { + return 0; + } + } else { + return 0; + } + + /* Substitute case-sensitive (or lowercase) persistent class constants */ + if (c && Z_TYPE_P(c) < IS_OBJECT) { + ZVAL_DUP(zv, c); + return 1; + } + + return 0; +} + void zend_init_list(void *result, void *item) /* {{{ */ { void** list = emalloc(sizeof(void*) * 2); @@ -1627,13 +1662,6 @@ ZEND_API size_t zend_dirname(char *path, size_t len) } /* }}} */ -static inline zend_bool zend_string_equals_str_ci(zend_string *str1, zend_string *str2) /* {{{ */ -{ - return str1->len == str2->len - && !zend_binary_strcasecmp(str1->val, str1->len, str2->val, str2->len); -} -/* }}} */ - static void zend_adjust_for_fetch_type(zend_op *opline, uint32_t type) /* {{{ */ { switch (type & BP_VAR_MASK) { @@ -5814,30 +5842,32 @@ void zend_compile_class_const(znode *result, zend_ast *ast) /* {{{ */ znode class_node, const_node; zend_op *opline, *class_op = NULL; + zend_string *resolved_name; + + zend_eval_const_expr(&class_ast); + zend_eval_const_expr(&const_ast); + + if (class_ast->kind == ZEND_AST_ZVAL) { + resolved_name = zend_resolve_class_name_ast(class_ast); + if (const_ast->kind == ZEND_AST_ZVAL && zend_try_ct_eval_class_const(&result->u.constant, resolved_name, zend_ast_get_str(const_ast))) { + result->op_type = IS_CONST; + zend_string_release(resolved_name); + return; + } + } if (zend_is_const_default_class_ref(class_ast)) { class_node.op_type = IS_CONST; - ZVAL_STR(&class_node.u.constant, zend_resolve_class_name_ast(class_ast)); + ZVAL_STR(&class_node.u.constant, resolved_name); } else { + if (class_ast->kind == ZEND_AST_ZVAL) { + zend_string_release(resolved_name); + } class_op = zend_compile_class_ref(&class_node, class_ast); } zend_compile_expr(&const_node, const_ast); - 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)) { - zval *const_zv = zend_hash_find(&CG(active_class_entry)->constants_table, Z_STR(const_node.u.constant)); - if (const_zv && Z_TYPE_P(const_zv) < IS_CONSTANT) { - CG(active_op_array)->last--; - CG(active_op_array)->T--; - - result->op_type = IS_CONST; - ZVAL_COPY(&result->u.constant, const_zv); - - zend_string_release(Z_STR(const_node.u.constant)); - return; - } - } - opline = zend_emit_op_tmp(result, ZEND_FETCH_CONSTANT, NULL, &const_node); zend_set_class_name_op1(opline, &class_node); @@ -5877,8 +5907,8 @@ void zend_compile_resolve_class_name(znode *result, zend_ast *ast) /* {{{ */ ZVAL_STR_COPY(&result->u.constant, CG(active_class_entry)->name); } break; - case ZEND_FETCH_CLASS_STATIC: - case ZEND_FETCH_CLASS_PARENT: + case ZEND_FETCH_CLASS_STATIC: + case ZEND_FETCH_CLASS_PARENT: if (!CG(active_class_entry)) { zend_error_noreturn(E_COMPILE_ERROR, "Cannot access %s::class when no class scope is active", @@ -6555,6 +6585,30 @@ void zend_eval_const_expr(zend_ast **ast_ptr) /* {{{ */ zend_string_release(resolved_name); break; } + case ZEND_AST_CLASS_CONST: + { + zend_ast *class_ast = ast->child[0]; + zend_ast *name_ast = ast->child[1]; + zend_string *resolved_name; + + zend_eval_const_expr(&class_ast); + zend_eval_const_expr(&name_ast); + + if (class_ast->kind != ZEND_AST_ZVAL || name_ast->kind != ZEND_AST_ZVAL) { + return; + } + + resolved_name = zend_resolve_class_name_ast(class_ast); + + if (!zend_try_ct_eval_class_const(&result, resolved_name, zend_ast_get_str(name_ast))) { + zend_string_release(resolved_name); + return; + } + + zend_string_release(resolved_name); + break; + } + default: return; } diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 92b5d9da5f..51c2c15405 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -2619,54 +2619,6 @@ ZEND_METHOD(reflection_parameter, getDefaultValue) } /* }}} */ -/* {{{ proto public bool ReflectionParameter::isDefaultValueConstant() - Returns whether the default value of this parameter is constant */ -ZEND_METHOD(reflection_parameter, isDefaultValueConstant) -{ - zend_op *precv; - parameter_reference *param; - - if (zend_parse_parameters_none() == FAILURE) { - return; - } - - param = _reflection_param_get_default_param(INTERNAL_FUNCTION_PARAM_PASSTHRU); - if (!param) { - RETURN_FALSE; - } - - precv = _reflection_param_get_default_precv(INTERNAL_FUNCTION_PARAM_PASSTHRU, param); - if (precv && Z_TYPE_P(RT_CONSTANT(¶m->fptr->op_array, precv->op2)) == IS_CONSTANT) { - RETURN_TRUE; - } - - RETURN_FALSE; -} -/* }}} */ - -/* {{{ proto public mixed ReflectionParameter::getDefaultValueConstantName() - Returns the default value's constant name if default value is constant or null */ -ZEND_METHOD(reflection_parameter, getDefaultValueConstantName) -{ - zend_op *precv; - parameter_reference *param; - - if (zend_parse_parameters_none() == FAILURE) { - return; - } - - param = _reflection_param_get_default_param(INTERNAL_FUNCTION_PARAM_PASSTHRU); - if (!param) { - return; - } - - precv = _reflection_param_get_default_precv(INTERNAL_FUNCTION_PARAM_PASSTHRU, param); - if (precv && Z_TYPE_P(RT_CONSTANT(¶m->fptr->op_array, precv->op2)) == IS_CONSTANT) { - RETURN_STR(zend_string_copy(Z_STR_P(RT_CONSTANT(¶m->fptr->op_array, precv->op2)))); - } -} -/* }}} */ - /* {{{ proto public bool ReflectionParameter::isVariadic() Returns whether this parameter is a variadic parameter */ ZEND_METHOD(reflection_parameter, isVariadic) @@ -6038,8 +5990,6 @@ static const zend_function_entry reflection_parameter_functions[] = { ZEND_ME(reflection_parameter, isOptional, arginfo_reflection__void, 0) ZEND_ME(reflection_parameter, isDefaultValueAvailable, arginfo_reflection__void, 0) ZEND_ME(reflection_parameter, getDefaultValue, arginfo_reflection__void, 0) - ZEND_ME(reflection_parameter, isDefaultValueConstant, arginfo_reflection__void, 0) - ZEND_ME(reflection_parameter, getDefaultValueConstantName, arginfo_reflection__void, 0) ZEND_ME(reflection_parameter, isVariadic, arginfo_reflection__void, 0) PHP_FE_END }; diff --git a/ext/reflection/tests/ReflectionParameter_DefaultValue.phpt b/ext/reflection/tests/ReflectionParameter_DefaultValue.phpt new file mode 100644 index 0000000000..b3f77ca2b5 --- /dev/null +++ b/ext/reflection/tests/ReflectionParameter_DefaultValue.phpt @@ -0,0 +1,46 @@ +--TEST-- +ReflectionParameter::getDefaultValue() with constants and non-compile-time ASTs +--FILE-- +getParameters() as $param) { + if($param->isDefaultValueAvailable()) { + var_dump($param->getDefaultValue()); + } +} + +class Foo2 { + const bar = 'Foo2::bar'; +} + +class Foo { + const bar = 'Foo::bar'; + + public function baz($param1 = self::bar, $param2 = Foo2::bar, $param3 = CONST_TEST_1 . "+string") { + } +} + +$method = new ReflectionMethod('Foo', 'baz'); +$params = $method->getParameters(); + +foreach ($params as $param) { + if ($param->isDefaultValueAvailable()) { + var_dump($param->getDefaultValue()); + } +} +?> +==DONE== +--EXPECT-- +array(0) { +} +string(6) "const1" +string(8) "Foo::bar" +string(9) "Foo2::bar" +string(13) "const1+string" +==DONE== diff --git a/ext/reflection/tests/ReflectionParameter_DefaultValueConstant_basic1.phpt b/ext/reflection/tests/ReflectionParameter_DefaultValueConstant_basic1.phpt deleted file mode 100644 index cdd00d2624..0000000000 --- a/ext/reflection/tests/ReflectionParameter_DefaultValueConstant_basic1.phpt +++ /dev/null @@ -1,52 +0,0 @@ ---TEST-- -ReflectionParameter::isDefaultValueConstant() && getDefaultValueConstantName() ---FILE-- -getParameters() as $param) { - if($param->getName() == 'test1') { - var_dump($param->isDefaultValueConstant()); - } - if($param->getName() == 'test2') { - var_dump($param->isDefaultValueConstant()); - } - if($param->isDefaultValueAvailable() && $param->isDefaultValueConstant()) { - var_dump($param->getDefaultValueConstantName()); - } -} - -class Foo2 { - const bar = 'Foo2::bar'; -} - -class Foo { - const bar = 'Foo::bar'; - - public function baz($param1 = self::bar, $param2=Foo2::bar, $param3=CONST_TEST_1) { - } -} - -$method = new ReflectionMethod('Foo', 'baz'); -$params = $method->getParameters(); - -foreach ($params as $param) { - if ($param->isDefaultValueConstant()) { - var_dump($param->getDefaultValueConstantName()); - } -} -?> -==DONE== ---EXPECT-- -bool(false) -bool(true) -string(12) "CONST_TEST_1" -string(9) "self::bar" -string(9) "Foo2::bar" -string(12) "CONST_TEST_1" -==DONE== diff --git a/ext/reflection/tests/ReflectionParameter_DefaultValueConstant_basic2.phpt b/ext/reflection/tests/ReflectionParameter_DefaultValueConstant_basic2.phpt deleted file mode 100644 index 1ee9e93735..0000000000 --- a/ext/reflection/tests/ReflectionParameter_DefaultValueConstant_basic2.phpt +++ /dev/null @@ -1,30 +0,0 @@ ---TEST-- -ReflectionParameter::isDefaultValueConstant() && getDefaultValueConstantName() for namespace ---FILE-- -getParameters() as $param) { - if($param->isDefaultValueAvailable() && $param->isDefaultValueConstant()) { - echo $param->getDefaultValueConstantName() . "\n"; - } - } - echo "==DONE=="; -} -?> ---EXPECT-- -ReflectionTestNamespace\TestClass::TEST_CONST_2 -ReflectionTestNamespace\CONST_TEST_1 -==DONE== diff --git a/ext/reflection/tests/ReflectionParameter_DefaultValueConstant_error.phpt b/ext/reflection/tests/ReflectionParameter_DefaultValueConstant_error.phpt deleted file mode 100644 index a2c2d24582..0000000000 --- a/ext/reflection/tests/ReflectionParameter_DefaultValueConstant_error.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -ReflectionParameter::getDefaultValueConstant() should raise exception on non optional parameter ---FILE-- -getParameters() as $param) { - try { - echo $param->getDefaultValueConstantName() . "\n"; - } - catch(ReflectionException $e) { - echo $e->getMessage() . "\n"; - } -} -?> ---EXPECT-- -Internal error: Failed to retrieve the default value -CONST_TEST_1