]> granicus.if.org Git - php/commitdiff
Revert "Revert "Improve and generalize class constant substitution""
authorBob Weinand <bobwei9@hotmail.com>
Tue, 10 Feb 2015 14:43:23 +0000 (15:43 +0100)
committerBob Weinand <bobwei9@hotmail.com>
Tue, 10 Feb 2015 14:47:17 +0000 (15:47 +0100)
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.)

Zend/zend_compile.c
ext/reflection/php_reflection.c
ext/reflection/tests/ReflectionParameter_DefaultValue.phpt [new file with mode: 0644]
ext/reflection/tests/ReflectionParameter_DefaultValueConstant_basic1.phpt [deleted file]
ext/reflection/tests/ReflectionParameter_DefaultValueConstant_basic2.phpt [deleted file]
ext/reflection/tests/ReflectionParameter_DefaultValueConstant_error.phpt [deleted file]

index bdd0c17583b9c05ef01e02deef69afa5c8ee3896..60d8472677d4d3380874f001d90c95094dad21be 100644 (file)
@@ -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;
        }
index 92b5d9da5fc0f10c4bbfdccb606aeed41e5e4b3c..51c2c154052b712cfe2ffc5fedb2940dccd8c48d 100644 (file)
@@ -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(&param->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(&param->fptr->op_array, precv->op2)) == IS_CONSTANT) {
-               RETURN_STR(zend_string_copy(Z_STR_P(RT_CONSTANT(&param->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 (file)
index 0000000..b3f77ca
--- /dev/null
@@ -0,0 +1,46 @@
+--TEST--
+ReflectionParameter::getDefaultValue() with constants and non-compile-time ASTs
+--FILE--
+<?php
+
+define("CONST_TEST_1", "const1");
+
+function ReflectionParameterTest($test1=array(), $test2 = CONST_TEST_1) {
+       echo $test;
+}
+$reflect = new ReflectionFunction('ReflectionParameterTest');
+foreach($reflect->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 (file)
index cdd00d2..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
---TEST--
-ReflectionParameter::isDefaultValueConstant() && getDefaultValueConstantName()
---FILE--
-<?php
-
-define("CONST_TEST_1", "const1");
-
-function ReflectionParameterTest($test1=array(), $test2 = CONST_TEST_1) {
-       echo $test;
-}
-$reflect = new ReflectionFunction('ReflectionParameterTest');
-foreach($reflect->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 (file)
index 1ee9e93..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
---TEST--
-ReflectionParameter::isDefaultValueConstant() && getDefaultValueConstantName() for namespace
---FILE--
-<?php
-
-namespace ReflectionTestNamespace {
-       CONST TEST_CONST_1 = "Test Const 1";
-
-       class TestClass {
-               const TEST_CONST_2 = "Test Const 2 in class";
-       }
-}
-
-namespace {
-       function ReflectionParameterTest($test=ReflectionTestNamespace\TestClass::TEST_CONST_2, $test2 = ReflectionTestNamespace\CONST_TEST_1) {
-               echo $test;
-       }
-       $reflect = new ReflectionFunction('ReflectionParameterTest');
-       foreach($reflect->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 (file)
index a2c2d24..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
---TEST--
-ReflectionParameter::getDefaultValueConstant() should raise exception on non optional parameter
---FILE--
-<?php
-
-define("CONST_TEST_1", "const1");
-
-function ReflectionParameterTest($test, $test2 = CONST_TEST_1) {
-       echo $test;
-}
-$reflect = new ReflectionFunction('ReflectionParameterTest');
-foreach($reflect->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