Skip to content

Commit 13a9555

Browse files
committed
Implemented FR #61602 Allow access to name of constant used as default value
This is an improved commit for FR #61602, this fixed the previous commit 054f3e3's C99 compiler compatibility issue
1 parent 5ebb0e5 commit 13a9555

4 files changed

+210
-12
lines changed

ext/reflection/php_reflection.c

Lines changed: 103 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1457,6 +1457,54 @@ static void _reflection_export(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *c
14571457
}
14581458
/* }}} */
14591459

1460+
/* {{{ _reflection_param_get_default_param */
1461+
static parameter_reference *_reflection_param_get_default_param(INTERNAL_FUNCTION_PARAMETERS)
1462+
{
1463+
reflection_object *intern;
1464+
parameter_reference *param;
1465+
1466+
intern = (reflection_object *) zend_object_store_get_object(getThis() TSRMLS_CC);
1467+
if (intern == NULL || intern->ptr == NULL) {
1468+
if (EG(exception) && Z_OBJCE_P(EG(exception)) == reflection_exception_ptr) {
1469+
return NULL;
1470+
}
1471+
php_error_docref(NULL TSRMLS_CC, E_ERROR, "Internal error: Failed to retrieve the reflection object");
1472+
}
1473+
1474+
param = intern->ptr;
1475+
if (param->fptr->type != ZEND_USER_FUNCTION) {
1476+
zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Cannot determine default value for internal functions");
1477+
return NULL;
1478+
}
1479+
1480+
if (param->offset < param->required) {
1481+
zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Parameter is not optional");
1482+
return NULL;
1483+
}
1484+
1485+
return param;
1486+
}
1487+
/* }}} */
1488+
1489+
/* {{{ _reflection_param_get_default_precv */
1490+
static zend_op *_reflection_param_get_default_precv(INTERNAL_FUNCTION_PARAMETERS, parameter_reference *param)
1491+
{
1492+
zend_op *precv;
1493+
1494+
if (param == NULL) {
1495+
return NULL;
1496+
}
1497+
1498+
precv = _get_recv_op((zend_op_array*)param->fptr, param->offset);
1499+
if (!precv || precv->opcode != ZEND_RECV_INIT || precv->op2_type == IS_UNUSED) {
1500+
zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Internal error");
1501+
return NULL;
1502+
}
1503+
1504+
return precv;
1505+
}
1506+
/* }}} */
1507+
14601508
/* {{{ Preventing __clone from being called */
14611509
ZEND_METHOD(reflection, __clone)
14621510
{
@@ -2535,27 +2583,20 @@ ZEND_METHOD(reflection_parameter, isDefaultValueAvailable)
25352583
Returns the default value of this parameter or throws an exception */
25362584
ZEND_METHOD(reflection_parameter, getDefaultValue)
25372585
{
2538-
reflection_object *intern;
25392586
parameter_reference *param;
25402587
zend_op *precv;
25412588

25422589
if (zend_parse_parameters_none() == FAILURE) {
25432590
return;
25442591
}
2545-
GET_REFLECTION_OBJECT_PTR(param);
25462592

2547-
if (param->fptr->type != ZEND_USER_FUNCTION)
2548-
{
2549-
zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Cannot determine default value for internal functions");
2593+
param = _reflection_param_get_default_param(INTERNAL_FUNCTION_PARAM_PASSTHRU);
2594+
if (!param) {
25502595
return;
25512596
}
2552-
if (param->offset < param->required) {
2553-
zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Parameter is not optional");
2554-
return;
2555-
}
2556-
precv = _get_recv_op((zend_op_array*)param->fptr, param->offset);
2557-
if (!precv || precv->opcode != ZEND_RECV_INIT || precv->op2_type == IS_UNUSED) {
2558-
zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Internal error");
2597+
2598+
precv = _reflection_param_get_default_precv(INTERNAL_FUNCTION_PARAM_PASSTHRU, param);
2599+
if (!precv) {
25592600
return;
25602601
}
25612602

@@ -2568,6 +2609,54 @@ ZEND_METHOD(reflection_parameter, getDefaultValue)
25682609
}
25692610
/* }}} */
25702611

2612+
/* {{{ proto public bool ReflectionParameter::isDefaultValueConstant()
2613+
Returns whether the default value of this parameter is constant */
2614+
ZEND_METHOD(reflection_parameter, isDefaultValueConstant)
2615+
{
2616+
zend_op *precv;
2617+
parameter_reference *param;
2618+
2619+
if (zend_parse_parameters_none() == FAILURE) {
2620+
return;
2621+
}
2622+
2623+
param = _reflection_param_get_default_param(INTERNAL_FUNCTION_PARAM_PASSTHRU);
2624+
if (!param) {
2625+
RETURN_FALSE;
2626+
}
2627+
2628+
precv = _reflection_param_get_default_precv(INTERNAL_FUNCTION_PARAM_PASSTHRU, param);
2629+
if (precv && (Z_TYPE_P(precv->op2.zv) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT) {
2630+
RETURN_TRUE;
2631+
}
2632+
2633+
RETURN_FALSE;
2634+
}
2635+
/* }}} */
2636+
2637+
/* {{{ proto public mixed ReflectionParameter::getDefaultValueConstantName()
2638+
Returns the default value's constant name if default value is constant or null */
2639+
ZEND_METHOD(reflection_parameter, getDefaultValueConstantName)
2640+
{
2641+
zend_op *precv;
2642+
parameter_reference *param;
2643+
2644+
if (zend_parse_parameters_none() == FAILURE) {
2645+
return;
2646+
}
2647+
2648+
param = _reflection_param_get_default_param(INTERNAL_FUNCTION_PARAM_PASSTHRU);
2649+
if (!param) {
2650+
return;
2651+
}
2652+
2653+
precv = _reflection_param_get_default_precv(INTERNAL_FUNCTION_PARAM_PASSTHRU, param);
2654+
if (precv && (Z_TYPE_P(precv->op2.zv) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT) {
2655+
RETURN_STRINGL(Z_STRVAL_P(precv->op2.zv), Z_STRLEN_P(precv->op2.zv), 1);
2656+
}
2657+
}
2658+
/* }}} */
2659+
25712660
/* {{{ proto public static mixed ReflectionMethod::export(mixed class, string name [, bool return]) throws ReflectionException
25722661
Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
25732662
ZEND_METHOD(reflection_method, export)
@@ -5903,6 +5992,8 @@ static const zend_function_entry reflection_parameter_functions[] = {
59035992
ZEND_ME(reflection_parameter, isOptional, arginfo_reflection__void, 0)
59045993
ZEND_ME(reflection_parameter, isDefaultValueAvailable, arginfo_reflection__void, 0)
59055994
ZEND_ME(reflection_parameter, getDefaultValue, arginfo_reflection__void, 0)
5995+
ZEND_ME(reflection_parameter, isDefaultValueConstant, arginfo_reflection__void, 0)
5996+
ZEND_ME(reflection_parameter, getDefaultValueConstantName, arginfo_reflection__void, 0)
59065997
PHP_FE_END
59075998
};
59085999

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
--TEST--
2+
ReflectionParameter::isDefaultValueConstant() && getDefaultValueConstantName()
3+
--FILE--
4+
<?php
5+
6+
define("CONST_TEST_1", "const1");
7+
8+
function ReflectionParameterTest($test1=array(), $test2 = CONST_TEST_1) {
9+
echo $test;
10+
}
11+
$reflect = new ReflectionFunction('ReflectionParameterTest');
12+
foreach($reflect->getParameters() as $param) {
13+
if($param->getName() == 'test1') {
14+
var_dump($param->isDefaultValueConstant());
15+
}
16+
if($param->getName() == 'test2') {
17+
var_dump($param->isDefaultValueConstant());
18+
}
19+
if($param->isDefaultValueAvailable() && $param->isDefaultValueConstant()) {
20+
var_dump($param->getDefaultValueConstantName());
21+
}
22+
}
23+
24+
class Foo2 {
25+
const bar = 'Foo2::bar';
26+
}
27+
28+
class Foo {
29+
const bar = 'Foo::bar';
30+
31+
public function baz($param1 = self::bar, $param2=Foo2::bar, $param3=CONST_TEST_1) {
32+
}
33+
}
34+
35+
$method = new ReflectionMethod('Foo', 'baz');
36+
$params = $method->getParameters();
37+
38+
foreach ($params as $param) {
39+
if ($param->isDefaultValueConstant()) {
40+
var_dump($param->getDefaultValueConstantName());
41+
}
42+
}
43+
?>
44+
==DONE==
45+
--EXPECT--
46+
bool(false)
47+
bool(true)
48+
string(12) "CONST_TEST_1"
49+
string(9) "self::bar"
50+
string(9) "Foo2::bar"
51+
string(12) "CONST_TEST_1"
52+
==DONE==
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
--TEST--
2+
ReflectionParameter::isDefaultValueConstant() && getDefaultValueConstantName() for namespace
3+
--FILE--
4+
<?php
5+
6+
namespace ReflectionTestNamespace {
7+
CONST TEST_CONST_1 = "Test Const 1";
8+
9+
class TestClass {
10+
const TEST_CONST_2 = "Test Const 2 in class";
11+
}
12+
}
13+
14+
namespace {
15+
function ReflectionParameterTest($test=ReflectionTestNamespace\TestClass::TEST_CONST_2, $test2 = ReflectionTestNamespace\CONST_TEST_1) {
16+
echo $test;
17+
}
18+
$reflect = new ReflectionFunction('ReflectionParameterTest');
19+
foreach($reflect->getParameters() as $param) {
20+
if($param->isDefaultValueAvailable() && $param->isDefaultValueConstant()) {
21+
echo $param->getDefaultValueConstantName() . "\n";
22+
}
23+
}
24+
echo "==DONE==";
25+
}
26+
?>
27+
--EXPECT--
28+
ReflectionTestNamespace\TestClass::TEST_CONST_2
29+
ReflectionTestNamespace\CONST_TEST_1
30+
==DONE==
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--TEST--
2+
ReflectionParameter::getDefaultValueConstant() should raise exception on non optional parameter
3+
--FILE--
4+
<?php
5+
6+
define("CONST_TEST_1", "const1");
7+
8+
function ReflectionParameterTest($test, $test2 = CONST_TEST_1) {
9+
echo $test;
10+
}
11+
$reflect = new ReflectionFunction('ReflectionParameterTest');
12+
foreach($reflect->getParameters() as $param) {
13+
try {
14+
echo $param->getDefaultValueConstantName() . "\n";
15+
}
16+
catch(ReflectionException $e) {
17+
echo $e->getMessage() . "\n";
18+
}
19+
}
20+
?>
21+
==DONE==
22+
--EXPECT--
23+
Parameter is not optional
24+
CONST_TEST_1
25+
==DONE==

0 commit comments

Comments
 (0)