summaryrefslogtreecommitdiff
path: root/ext/reflection
diff options
context:
space:
mode:
authorReeze Xia <reeze.xia@gmail.com>2012-05-31 23:31:00 +0800
committerReeze Xia <reeze.xia@gmail.com>2012-05-31 23:31:00 +0800
commit13a9555342a4156a6150818234639b49a596ccd6 (patch)
treee90de3cef475f4773637513f7366cdf8bae1b36a /ext/reflection
parent5ebb0e520f4c31d09d9e5acd323162eca3fee0e3 (diff)
downloadphp-git-13a9555342a4156a6150818234639b49a596ccd6.tar.gz
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
Diffstat (limited to 'ext/reflection')
-rw-r--r--ext/reflection/php_reflection.c115
-rw-r--r--ext/reflection/tests/ReflectionParameter_DefaultValueConstant_basic1.phpt52
-rw-r--r--ext/reflection/tests/ReflectionParameter_DefaultValueConstant_basic2.phpt30
-rw-r--r--ext/reflection/tests/ReflectionParameter_DefaultValueConstant_error.phpt25
4 files changed, 210 insertions, 12 deletions
diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c
index 1cf65cee16..ac997fcfa4 100644
--- a/ext/reflection/php_reflection.c
+++ b/ext/reflection/php_reflection.c
@@ -1457,6 +1457,54 @@ 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;
+
+ intern = (reflection_object *) zend_object_store_get_object(getThis() TSRMLS_CC);
+ if (intern == NULL || intern->ptr == NULL) {
+ if (EG(exception) && Z_OBJCE_P(EG(exception)) == reflection_exception_ptr) {
+ return NULL;
+ }
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Internal error: Failed to retrieve the reflection object");
+ }
+
+ param = intern->ptr;
+ 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;
+
+ if (param == NULL) {
+ 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)
{
@@ -2535,27 +2583,20 @@ 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;
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");
+ param = _reflection_param_get_default_param(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+ if (!param) {
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");
+
+ precv = _reflection_param_get_default_precv(INTERNAL_FUNCTION_PARAM_PASSTHRU, param);
+ if (!precv) {
return;
}
@@ -2568,6 +2609,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(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 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(precv->op2.zv) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT) {
+ RETURN_STRINGL(Z_STRVAL_P(precv->op2.zv), Z_STRLEN_P(precv->op2.zv), 1);
+ }
+}
+/* }}} */
+
/* {{{ 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)
@@ -5903,6 +5992,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
};
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..984b06efe2
--- /dev/null
+++ b/ext/reflection/tests/ReflectionParameter_DefaultValueConstant_error.phpt
@@ -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==