diff options
| author | Bob Weinand <bobwei9@hotmail.com> | 2015-02-10 22:17:43 +0100 |
|---|---|---|
| committer | Bob Weinand <bobwei9@hotmail.com> | 2015-02-10 22:20:53 +0100 |
| commit | 2b3bebfa4cbc51f4d78cc089d31e96123aa1da20 (patch) | |
| tree | 76ecc49fbb5c2978f94b914a601736e978e90c4d | |
| parent | 087102c6d30fd36b6d7c68e63ad7056d7e1ca599 (diff) | |
| download | php-git-2b3bebfa4cbc51f4d78cc089d31e96123aa1da20.tar.gz | |
Revert removal of two ReflectionParameter functions
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)
| -rw-r--r-- | Zend/zend_compile.c | 14 | ||||
| -rw-r--r-- | Zend/zend_compile.h | 3 | ||||
| -rw-r--r-- | ext/reflection/php_reflection.c | 50 | ||||
| -rw-r--r-- | ext/reflection/tests/ReflectionParameter_DefaultValue.phpt | 46 | ||||
| -rw-r--r-- | ext/reflection/tests/ReflectionParameter_DefaultValueConstant_basic1.phpt | 52 | ||||
| -rw-r--r-- | ext/reflection/tests/ReflectionParameter_DefaultValueConstant_basic2.phpt | 30 | ||||
| -rw-r--r-- | ext/reflection/tests/ReflectionParameter_DefaultValueConstant_error.phpt | 23 |
7 files changed, 169 insertions, 49 deletions
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 60d8472677..b4ce59ca35 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -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; diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 8a9b37cc6c..171fdcfbf2 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -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 diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 51c2c15405..92b5d9da5f 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -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(¶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) @@ -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 index b3f77ca2b5..0000000000 --- a/ext/reflection/tests/ReflectionParameter_DefaultValue.phpt +++ /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 index 0000000000..cdd00d2624 --- /dev/null +++ b/ext/reflection/tests/ReflectionParameter_DefaultValueConstant_basic1.phpt @@ -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 index 0000000000..1ee9e93735 --- /dev/null +++ b/ext/reflection/tests/ReflectionParameter_DefaultValueConstant_basic2.phpt @@ -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 index 0000000000..a2c2d24582 --- /dev/null +++ b/ext/reflection/tests/ReflectionParameter_DefaultValueConstant_error.phpt @@ -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 |
