Browse Source

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)
pull/1075/head
Bob Weinand 11 years ago
parent
commit
2b3bebfa4c
  1. 14
      Zend/zend_compile.c
  2. 3
      Zend/zend_compile.h
  3. 50
      ext/reflection/php_reflection.c
  4. 46
      ext/reflection/tests/ReflectionParameter_DefaultValue.phpt
  5. 52
      ext/reflection/tests/ReflectionParameter_DefaultValueConstant_basic1.phpt
  6. 30
      ext/reflection/tests/ReflectionParameter_DefaultValueConstant_basic2.phpt
  7. 23
      ext/reflection/tests/ReflectionParameter_DefaultValueConstant_error.phpt

14
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;

3
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

50
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(&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
};

46
ext/reflection/tests/ReflectionParameter_DefaultValue.phpt

@ -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==

52
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==

30
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==

23
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
Loading…
Cancel
Save