Skip to content

Commit

Permalink
Merge branch 'add-const-name' of git://github.com/reeze/php-src into …
Browse files Browse the repository at this point in the history
…PHP-5.4
  • Loading branch information
sebastianbergmann committed May 15, 2012
2 parents 0ad53bf + 6712d0d commit 83449b4
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 16 deletions.
2 changes: 2 additions & 0 deletions NEWS
Expand Up @@ -171,6 +171,8 @@ PHP NEWS
bytes). (Nikita Popov)

- Reflection:
. Implemented FR #61602 (Allow access to the name of constant
used as function/method parameter's default value). (reeze.xia@gmail.com)
. Fixed bug #60968 (Late static binding doesn't work with
ReflectionMethod::invokeArgs()). (Laruence)

Expand Down
100 changes: 84 additions & 16 deletions ext/reflection/php_reflection.c
Expand Up @@ -1457,6 +1457,49 @@ static void _reflection_export(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *c
}
/* }}} */

/* {{{ _reflection_param_get_default_param */
static parameter_reference *_reflection_param_get_default_param(INTERNAL_FUNCTION_PARAMETERS)
{
reflection_object *intern;
parameter_reference *param;

GET_REFLECTION_OBJECT_PTR(param);

if (param->fptr->type != ZEND_USER_FUNCTION)
{
zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Cannot determine default value for internal functions");
return NULL;
}

if (param->offset < param->required) {
zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Parameter is not optional");
return NULL;
}

return param;
}
/* }}} */

/* {{{ _reflection_param_get_default_precv */
static zend_op *_reflection_param_get_default_precv(INTERNAL_FUNCTION_PARAMETERS, parameter_reference *param)
{
zend_op *precv;

param = param ? param : _reflection_param_get_default_param(INTERNAL_FUNCTION_PARAM_PASSTHRU);
if (!param) {
return NULL;
}

precv = _get_recv_op((zend_op_array*)param->fptr, param->offset);
if (!precv || precv->opcode != ZEND_RECV_INIT || precv->op2_type == IS_UNUSED) {
zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Internal error");
return NULL;
}

return precv;
}
/* }}} */

/* {{{ Preventing __clone from being called */
ZEND_METHOD(reflection, __clone)
{
Expand Down Expand Up @@ -2535,27 +2578,14 @@ ZEND_METHOD(reflection_parameter, isDefaultValueAvailable)
Returns the default value of this parameter or throws an exception */
ZEND_METHOD(reflection_parameter, getDefaultValue)
{
reflection_object *intern;
parameter_reference *param;
zend_op *precv;
parameter_reference *param = _reflection_param_get_default_param(INTERNAL_FUNCTION_PARAM_PASSTHRU);
zend_op *precv = _reflection_param_get_default_precv(INTERNAL_FUNCTION_PARAM_PASSTHRU, param);

if (zend_parse_parameters_none() == FAILURE) {
return;
}
GET_REFLECTION_OBJECT_PTR(param);

if (param->fptr->type != ZEND_USER_FUNCTION)
{
zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Cannot determine default value for internal functions");
return;
}
if (param->offset < param->required) {
zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Parameter is not optional");
return;
}
precv = _get_recv_op((zend_op_array*)param->fptr, param->offset);
if (!precv || precv->opcode != ZEND_RECV_INIT || precv->op2_type == IS_UNUSED) {
zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Internal error");
if (!(param && precv)) {
return;
}

Expand All @@ -2568,6 +2598,42 @@ 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 = _reflection_param_get_default_precv(INTERNAL_FUNCTION_PARAM_PASSTHRU, NULL);

if (zend_parse_parameters_none() == FAILURE) {
return;
}

if (precv && (Z_TYPE_P(precv->op2.zv) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT) {
RETURN_TRUE;
}

RETURN_FALSE;
}
/* }}} */

/* {{{ proto public mixed ReflectionParameter::getDefaultValueConstantName()
Returns the default value's constant name if default value is constant or false */
ZEND_METHOD(reflection_parameter, getDefaultValueConstantName)
{
zend_op *precv = _reflection_param_get_default_precv(INTERNAL_FUNCTION_PARAM_PASSTHRU, NULL);

if (zend_parse_parameters_none() == FAILURE) {
return;
}

if (precv && (Z_TYPE_P(precv->op2.zv) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT) {
RETURN_STRING(Z_STRVAL_P(precv->op2.zv), 1);
}

RETURN_FALSE;
}
/* }}} */

/* {{{ proto public static mixed ReflectionMethod::export(mixed class, string name [, bool return]) throws ReflectionException
Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
ZEND_METHOD(reflection_method, export)
Expand Down Expand Up @@ -5903,6 +5969,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)
PHP_FE_END
};

Expand Down
@@ -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==
@@ -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==
@@ -0,0 +1,25 @@
--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";
}
}
?>
==DONE==
--EXPECT--
Parameter is not optional
CONST_TEST_1
==DONE==

0 comments on commit 83449b4

Please sign in to comment.