]> granicus.if.org Git - php/commitdiff
Revert removal of two ReflectionParameter functions
authorBob Weinand <bobwei9@hotmail.com>
Tue, 10 Feb 2015 21:17:43 +0000 (22:17 +0100)
committerBob Weinand <bobwei9@hotmail.com>
Tue, 10 Feb 2015 21:20:53 +0000 (22:20 +0100)
Rather fix them for now by exempting function parameter defaults from *any* (non-ct) constant substitution (also from persistent constant substitution, which was already broken before)

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

index 60d8472677d4d3380874f001d90c95094dad21be..b4ce59ca353d6d9156bcdb48b1937f216d15e94f 100644 (file)
@@ -1179,9 +1179,9 @@ static zend_bool zend_try_ct_eval_const(zval *zv, zend_string *name, zend_bool i
        /* 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)))
-       ) {
+             ((c->flags & CONST_PERSISTENT) && !(CG(compiler_options) & ZEND_COMPILE_NO_PERSISTENT_CONSTANT_SUBSTITUTION))
+          || (Z_TYPE(c->value) < IS_OBJECT && !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION))
+       )) {
                ZVAL_DUP(zv, &c->value);
                return 1;
        }
@@ -1224,6 +1224,10 @@ static zend_bool zend_try_ct_eval_class_const(zval *zv, zend_string *class_name,
                return 0;
        }
 
+       if (CG(compiler_options) & ZEND_COMPILE_NO_PERSISTENT_CONSTANT_SUBSTITUTION) {
+               return 0;
+       }
+
        /* Substitute case-sensitive (or lowercase) persistent class constants */
        if (c && Z_TYPE_P(c) < IS_OBJECT) {
                ZVAL_DUP(zv, c);
@@ -3929,9 +3933,13 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, zend_bool is_
                                        "Variadic parameter cannot have a default value");
                        }
                } else if (default_ast) {
+                       /* we cannot substitute constants here or it will break ReflectionParameter::getDefaultValueConstantName() and ReflectionParameter::isDefaultValueConstant() */
+                       uint32_t cops = CG(compiler_options);
+                       CG(compiler_options) |= ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION | ZEND_COMPILE_NO_PERSISTENT_CONSTANT_SUBSTITUTION;
                        opcode = ZEND_RECV_INIT;
                        default_node.op_type = IS_CONST;
                        zend_const_expr_to_zval(&default_node.u.constant, default_ast);
+                       CG(compiler_options) = cops;
                } else {
                        opcode = ZEND_RECV;
                        default_node.op_type = IS_UNUSED;
index 8a9b37cc6c6f8f39535cd62f78f0ff4211e1ae9f..171fdcfbf29874b141adc0f470457f8962775963 100644 (file)
@@ -927,6 +927,9 @@ END_EXTERN_C()
 /* disable usage of builtin instruction for strlen() */
 #define ZEND_COMPILE_NO_BUILTIN_STRLEN                 (1<<6)
 
+/* disable substitution of persistent constants at compile-time */
+#define ZEND_COMPILE_NO_PERSISTENT_CONSTANT_SUBSTITUTION       (1<<7)
+
 /* The default value for CG(compiler_options) */
 #define ZEND_COMPILE_DEFAULT                                   ZEND_COMPILE_HANDLE_OP_ARRAY
 
index 51c2c154052b712cfe2ffc5fedb2940dccd8c48d..92b5d9da5fc0f10c4bbfdccb606aeed41e5e4b3c 100644 (file)
@@ -2619,6 +2619,54 @@ 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)
@@ -5990,6 +6038,8 @@ 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
deleted file mode 100644 (file)
index b3f77ca..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
---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
new file mode 100644 (file)
index 0000000..cdd00d2
--- /dev/null
@@ -0,0 +1,52 @@
+--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
new file mode 100644 (file)
index 0000000..1ee9e93
--- /dev/null
@@ -0,0 +1,30 @@
+--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
new file mode 100644 (file)
index 0000000..a2c2d24
--- /dev/null
@@ -0,0 +1,23 @@
+--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