summaryrefslogtreecommitdiff
path: root/ext/reflection
diff options
context:
space:
mode:
Diffstat (limited to 'ext/reflection')
-rw-r--r--ext/reflection/php_reflection.c57
-rw-r--r--ext/reflection/tests/ReflectionClass_newInstanceWithoutConstructor.phpt7
-rw-r--r--ext/reflection/tests/ReflectionFunction_isVariadic_basic.phpt18
-rw-r--r--ext/reflection/tests/ReflectionParameter_canBePassedByValue.phpt4
-rw-r--r--ext/reflection/tests/ReflectionParameter_isVariadic_basic.phpt24
-rw-r--r--ext/reflection/tests/ReflectionParameter_toString_basic.phpt3
-rw-r--r--ext/reflection/tests/bug64007.phpt2
7 files changed, 102 insertions, 13 deletions
diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c
index 31d836a7ac..8e5fcadef4 100644
--- a/ext/reflection/php_reflection.c
+++ b/ext/reflection/php_reflection.c
@@ -681,8 +681,8 @@ static zend_op* _get_recv_op(zend_op_array *op_array, zend_uint offset)
++offset;
while (op < end) {
- if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT)
- && op->op1.num == (long)offset)
+ if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT
+ || op->opcode == ZEND_RECV_VARIADIC) && op->op1.num == (long)offset)
{
return op;
}
@@ -715,6 +715,9 @@ static void _parameter_string(string *str, zend_function *fptr, struct _zend_arg
if (arg_info->pass_by_reference) {
string_write(str, "&", sizeof("&")-1);
}
+ if (arg_info->is_variadic) {
+ string_write(str, "...", sizeof("...")-1);
+ }
if (arg_info->name) {
string_printf(str, "$%s", arg_info->name);
} else {
@@ -725,12 +728,17 @@ static void _parameter_string(string *str, zend_function *fptr, struct _zend_arg
if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2_type != IS_UNUSED) {
zval *zv, zv_copy;
int use_copy;
+ zend_class_entry *old_scope;
+
string_write(str, " = ", sizeof(" = ")-1);
ALLOC_ZVAL(zv);
*zv = *precv->op2.zv;
zval_copy_ctor(zv);
INIT_PZVAL(zv);
- zval_update_constant_ex(&zv, (void*)1, fptr->common.scope TSRMLS_CC);
+ old_scope = EG(scope);
+ EG(scope) = fptr->common.scope;
+ zval_update_constant_ex(&zv, 1, NULL TSRMLS_CC);
+ EG(scope) = old_scope;
if (Z_TYPE_P(zv) == IS_BOOL) {
if (Z_LVAL_P(zv)) {
string_write(str, "true", sizeof("true")-1);
@@ -2576,6 +2584,7 @@ ZEND_METHOD(reflection_parameter, getDefaultValue)
{
parameter_reference *param;
zend_op *precv;
+ zend_class_entry *old_scope;
if (zend_parse_parameters_none() == FAILURE) {
return;
@@ -2593,11 +2602,13 @@ ZEND_METHOD(reflection_parameter, getDefaultValue)
*return_value = *precv->op2.zv;
INIT_PZVAL(return_value);
- if ((Z_TYPE_P(return_value) & IS_CONSTANT_TYPE_MASK) != IS_CONSTANT
- && (Z_TYPE_P(return_value) & IS_CONSTANT_TYPE_MASK) != IS_CONSTANT_ARRAY) {
+ if (!IS_CONSTANT_TYPE(Z_TYPE_P(return_value))) {
zval_copy_ctor(return_value);
}
- zval_update_constant_ex(&return_value, (void*)0, param->fptr->common.scope TSRMLS_CC);
+ old_scope = EG(scope);
+ EG(scope) = param->fptr->common.scope;
+ zval_update_constant_ex(&return_value, 0, NULL TSRMLS_CC);
+ EG(scope) = old_scope;
}
/* }}} */
@@ -2649,6 +2660,22 @@ ZEND_METHOD(reflection_parameter, getDefaultValueConstantName)
}
/* }}} */
+/* {{{ proto public bool ReflectionParameter::isVariadic()
+ Returns whether this parameter is a variadic parameter */
+ZEND_METHOD(reflection_parameter, isVariadic)
+{
+ reflection_object *intern;
+ parameter_reference *param;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+ GET_REFLECTION_OBJECT_PTR(param);
+
+ RETVAL_BOOL(param->arg_info->is_variadic);
+}
+/* }}} */
+
/* {{{ 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)
@@ -3092,6 +3119,14 @@ ZEND_METHOD(reflection_function, isGenerator)
}
/* }}} */
+/* {{{ proto public bool ReflectionFunction::isVariadic()
+ Returns whether this function is variadic */
+ZEND_METHOD(reflection_function, isVariadic)
+{
+ _function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_VARIADIC);
+}
+/* }}} */
+
/* {{{ proto public bool ReflectionFunction::inNamespace()
Returns whether this function is defined in namespace */
ZEND_METHOD(reflection_function, inNamespace)
@@ -3384,8 +3419,8 @@ static void add_class_vars(zend_class_entry *ce, int statics, zval *return_value
/* this is necessary to make it able to work with default array
* properties, returned to user */
- if (Z_TYPE_P(prop_copy) == IS_CONSTANT_ARRAY || (Z_TYPE_P(prop_copy) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT) {
- zval_update_constant(&prop_copy, (void *) 1 TSRMLS_CC);
+ if (IS_CONSTANT_TYPE(Z_TYPE_P(prop_copy))) {
+ zval_update_constant(&prop_copy, 1 TSRMLS_CC);
}
add_assoc_zval(return_value, key, prop_copy);
@@ -4273,8 +4308,8 @@ ZEND_METHOD(reflection_class, newInstanceWithoutConstructor)
METHOD_NOTSTATIC(reflection_class_ptr);
GET_REFLECTION_OBJECT_PTR(ce);
- if (ce->create_object != NULL) {
- zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Class %s is an internal class that cannot be instantiated without invoking its constructor", ce->name);
+ if (ce->create_object != NULL && ce->ce_flags & ZEND_ACC_FINAL_CLASS) {
+ zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Class %s is an internal class marked as final that cannot be instantiated without invoking its constructor", ce->name);
}
object_init_ex(return_value, ce);
@@ -5706,6 +5741,7 @@ static const zend_function_entry reflection_function_abstract_functions[] = {
ZEND_ME(reflection_function, isInternal, arginfo_reflection__void, 0)
ZEND_ME(reflection_function, isUserDefined, arginfo_reflection__void, 0)
ZEND_ME(reflection_function, isGenerator, arginfo_reflection__void, 0)
+ ZEND_ME(reflection_function, isVariadic, arginfo_reflection__void, 0)
ZEND_ME(reflection_function, getClosureThis, arginfo_reflection__void, 0)
ZEND_ME(reflection_function, getClosureScopeClass, arginfo_reflection__void, 0)
ZEND_ME(reflection_function, getDocComment, arginfo_reflection__void, 0)
@@ -6008,6 +6044,7 @@ static const zend_function_entry reflection_parameter_functions[] = {
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/ReflectionClass_newInstanceWithoutConstructor.phpt b/ext/reflection/tests/ReflectionClass_newInstanceWithoutConstructor.phpt
index 1932dbfaf1..dfe3e7f8f7 100644
--- a/ext/reflection/tests/ReflectionClass_newInstanceWithoutConstructor.phpt
+++ b/ext/reflection/tests/ReflectionClass_newInstanceWithoutConstructor.phpt
@@ -20,13 +20,18 @@ var_dump($class->newInstanceWithoutConstructor());
$class = new ReflectionClass('DateTime');
var_dump($class->newInstanceWithoutConstructor());
+
+$class = new ReflectionClass('Generator');
+var_dump($class->newInstanceWithoutConstructor());
--EXPECTF--
object(Foo)#%d (0) {
}
object(stdClass)#%d (0) {
}
+object(DateTime)#%d (0) {
+}
-Fatal error: Uncaught exception 'ReflectionException' with message 'Class DateTime is an internal class that cannot be instantiated without invoking its constructor' in %sReflectionClass_newInstanceWithoutConstructor.php:%d
+Fatal error: Uncaught exception 'ReflectionException' with message 'Class Generator is an internal class marked as final that cannot be instantiated without invoking its constructor' in %sReflectionClass_newInstanceWithoutConstructor.php:%d
Stack trace:
#0 %sReflectionClass_newInstanceWithoutConstructor.php(%d): ReflectionClass->newInstanceWithoutConstructor()
#1 {main}
diff --git a/ext/reflection/tests/ReflectionFunction_isVariadic_basic.phpt b/ext/reflection/tests/ReflectionFunction_isVariadic_basic.phpt
new file mode 100644
index 0000000000..50b6bb495e
--- /dev/null
+++ b/ext/reflection/tests/ReflectionFunction_isVariadic_basic.phpt
@@ -0,0 +1,18 @@
+--TEST--
+ReflectionFunction::isVariadic()
+--FILE--
+<?php
+
+function test1($args) {}
+function test2(...$args) {}
+function test3($arg, ...$args) {}
+
+var_dump((new ReflectionFunction('test1'))->isVariadic());
+var_dump((new ReflectionFunction('test2'))->isVariadic());
+var_dump((new ReflectionFunction('test3'))->isVariadic());
+
+?>
+--EXPECT--
+bool(false)
+bool(true)
+bool(true)
diff --git a/ext/reflection/tests/ReflectionParameter_canBePassedByValue.phpt b/ext/reflection/tests/ReflectionParameter_canBePassedByValue.phpt
index 82c6200122..4772f6548d 100644
--- a/ext/reflection/tests/ReflectionParameter_canBePassedByValue.phpt
+++ b/ext/reflection/tests/ReflectionParameter_canBePassedByValue.phpt
@@ -61,6 +61,10 @@ Name: SORT_REGULAR_or_SORT_NUMERIC_or_SORT_STRING
Is passed by reference: yes
Can be passed by value: yes
+Name: more_array_and_sort_options
+Is passed by reference: yes
+Can be passed by value: yes
+
=> sort:
Name: arg
diff --git a/ext/reflection/tests/ReflectionParameter_isVariadic_basic.phpt b/ext/reflection/tests/ReflectionParameter_isVariadic_basic.phpt
new file mode 100644
index 0000000000..370edc388d
--- /dev/null
+++ b/ext/reflection/tests/ReflectionParameter_isVariadic_basic.phpt
@@ -0,0 +1,24 @@
+--TEST--
+ReflectionParameter::isVariadic()
+--FILE--
+<?php
+
+function test1($args) {}
+function test2(...$args) {}
+function test3($arg, ...$args) {}
+
+$r1 = new ReflectionFunction('test1');
+$r2 = new ReflectionFunction('test2');
+$r3 = new ReflectionFunction('test3');
+
+var_dump($r1->getParameters()[0]->isVariadic());
+var_dump($r2->getParameters()[0]->isVariadic());
+var_dump($r3->getParameters()[0]->isVariadic());
+var_dump($r3->getParameters()[1]->isVariadic());
+
+?>
+--EXPECT--
+bool(false)
+bool(true)
+bool(false)
+bool(true)
diff --git a/ext/reflection/tests/ReflectionParameter_toString_basic.phpt b/ext/reflection/tests/ReflectionParameter_toString_basic.phpt
index 268ced15ec..d1a23c758d 100644
--- a/ext/reflection/tests/ReflectionParameter_toString_basic.phpt
+++ b/ext/reflection/tests/ReflectionParameter_toString_basic.phpt
@@ -4,7 +4,7 @@ ReflectionParameter::__toString()
Stefan Koopmanschap <stefan@stefankoopmanschap.nl>
--FILE--
<?php
-function ReflectionParameterTest($test, $test2 = null) {
+function ReflectionParameterTest($test, $test2 = null, ...$test3) {
echo $test;
}
$reflect = new ReflectionFunction('ReflectionParameterTest');
@@ -17,4 +17,5 @@ foreach($params as $key => $value) {
--EXPECT--
Parameter #0 [ <required> $test ]
Parameter #1 [ <optional> $test2 = NULL ]
+Parameter #2 [ <optional> ...$test3 ]
==DONE==
diff --git a/ext/reflection/tests/bug64007.phpt b/ext/reflection/tests/bug64007.phpt
index 32ec6a5610..ae3ec50328 100644
--- a/ext/reflection/tests/bug64007.phpt
+++ b/ext/reflection/tests/bug64007.phpt
@@ -14,6 +14,6 @@ $generator = $reflection->newInstance();
var_dump($generator);
?>
--EXPECTF--
-string(97) "Class Generator is an internal class that cannot be instantiated without invoking its constructor"
+string(%d) "Class Generator is an internal class marked as final that cannot be instantiated without invoking its constructor"
Catchable fatal error: The "Generator" class is reserved for internal use and cannot be manually instantiated in %sbug64007.php on line %d