mirror of
https://github.com/bdnugget/php-src.git
synced 2026-11-07 09:17:29 +00:00
ReflectionFunctionAbstract::getClosureUsedVariables
Make a distinction at compile time between bind types for static variables getStaticVariables remains unchanged Fixes #80071
This commit is contained in:
10 files changed
+147
-15
No files matched your search
@@ -112,6 +112,9 @@ PHP NEWS
|
||||
. Convert resource<pspell> to object \PSpell\Dictionary. (Sara)
|
||||
. Convert resource<pspell config> to object \PSpell\Config. (Sara)
|
||||
|
||||
- Reflection:
|
||||
. Implement ReflectionFunctionAbstract::getClosureUsedVariables (krakjoe)
|
||||
|
||||
- Sodium:
|
||||
. Added the XChaCha20 stream cipher functions. (P.I.E. Security Team)
|
||||
. Added the Ristretto255 functions, which are available in libsodium 1.0.18.
|
||||
|
||||
+15
-7
@@ -234,15 +234,23 @@ static inline bool may_have_side_effects(
|
||||
}
|
||||
return 0;
|
||||
case ZEND_BIND_STATIC:
|
||||
if (op_array->static_variables
|
||||
&& (opline->extended_value & ZEND_BIND_REF) != 0) {
|
||||
zval *value =
|
||||
(zval*)((char*)op_array->static_variables->arData +
|
||||
(opline->extended_value & ~ZEND_BIND_REF));
|
||||
if (Z_TYPE_P(value) == IS_CONSTANT_AST) {
|
||||
/* AST may contain undefined constants */
|
||||
if (op_array->static_variables) {
|
||||
/* Implicit and Explicit bind static is effectively prologue of closure so
|
||||
report it has side effects like RECV, RECV_INIT; This allows us to
|
||||
reflect on the closure and discover used variable at runtime */
|
||||
if ((opline->extended_value & (ZEND_BIND_IMPLICIT|ZEND_BIND_EXPLICIT))) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((opline->extended_value & ZEND_BIND_REF) != 0) {
|
||||
zval *value =
|
||||
(zval*)((char*)op_array->static_variables->arData +
|
||||
(opline->extended_value & ~ZEND_BIND_REF));
|
||||
if (Z_TYPE_P(value) == IS_CONSTANT_AST) {
|
||||
/* AST may contain undefined constants */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
case ZEND_CHECK_VAR:
|
||||
|
||||
+6
-1
@@ -6875,6 +6875,7 @@ static void zend_compile_closure_uses(zend_ast *ast) /* {{{ */
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < list->children; ++i) {
|
||||
uint32_t mode = ZEND_BIND_EXPLICIT;
|
||||
zend_ast *var_ast = list->child[i];
|
||||
zend_string *var_name = zend_ast_get_str(var_ast);
|
||||
zval zv;
|
||||
@@ -6892,7 +6893,11 @@ static void zend_compile_closure_uses(zend_ast *ast) /* {{{ */
|
||||
|
||||
CG(zend_lineno) = zend_ast_get_lineno(var_ast);
|
||||
|
||||
zend_compile_static_var_common(var_name, &zv, var_ast->attr ? ZEND_BIND_REF : 0);
|
||||
if (var_ast->attr) {
|
||||
mode |= ZEND_BIND_REF;
|
||||
}
|
||||
|
||||
zend_compile_static_var_common(var_name, &zv, mode);
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -1057,6 +1057,7 @@ static zend_always_inline bool zend_check_arg_send_type(const zend_function *zf,
|
||||
#define ZEND_BIND_VAL 0
|
||||
#define ZEND_BIND_REF 1
|
||||
#define ZEND_BIND_IMPLICIT 2
|
||||
#define ZEND_BIND_EXPLICIT 4
|
||||
|
||||
#define ZEND_RETURNS_FUNCTION (1<<0)
|
||||
#define ZEND_RETURNS_VALUE (1<<1)
|
||||
|
||||
+1
-1
@@ -8698,7 +8698,7 @@ ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, UNUSED, REF)
|
||||
}
|
||||
ZEND_ASSERT(GC_REFCOUNT(ht) == 1);
|
||||
|
||||
value = (zval*)((char*)ht->arData + (opline->extended_value & ~(ZEND_BIND_REF|ZEND_BIND_IMPLICIT)));
|
||||
value = (zval*)((char*)ht->arData + (opline->extended_value & ~(ZEND_BIND_REF|ZEND_BIND_IMPLICIT|ZEND_BIND_EXPLICIT)));
|
||||
|
||||
if (opline->extended_value & ZEND_BIND_REF) {
|
||||
if (Z_TYPE_P(value) == IS_CONSTANT_AST) {
|
||||
|
||||
@@ -47434,7 +47434,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_STATIC_SPEC_CV_UNUSED_HAN
|
||||
}
|
||||
ZEND_ASSERT(GC_REFCOUNT(ht) == 1);
|
||||
|
||||
value = (zval*)((char*)ht->arData + (opline->extended_value & ~(ZEND_BIND_REF|ZEND_BIND_IMPLICIT)));
|
||||
value = (zval*)((char*)ht->arData + (opline->extended_value & ~(ZEND_BIND_REF|ZEND_BIND_IMPLICIT|ZEND_BIND_EXPLICIT)));
|
||||
|
||||
if (opline->extended_value & ZEND_BIND_REF) {
|
||||
if (Z_TYPE_P(value) == IS_CONSTANT_AST) {
|
||||
|
||||
@@ -1664,6 +1664,55 @@ ZEND_METHOD(ReflectionFunctionAbstract, getClosureScopeClass)
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Returns an associative array containing the closures lexical scope variables */
|
||||
ZEND_METHOD(ReflectionFunctionAbstract, getClosureUsedVariables)
|
||||
{
|
||||
reflection_object *intern;
|
||||
const zend_function *closure_func;
|
||||
|
||||
if (zend_parse_parameters_none() == FAILURE) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
GET_REFLECTION_OBJECT();
|
||||
|
||||
array_init(return_value);
|
||||
if (!Z_ISUNDEF(intern->obj)) {
|
||||
closure_func = zend_get_closure_method_def(Z_OBJ(intern->obj));
|
||||
if (closure_func == NULL ||
|
||||
closure_func->type != ZEND_USER_FUNCTION ||
|
||||
closure_func->op_array.static_variables == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
const zend_op_array *ops = &closure_func->op_array;
|
||||
|
||||
HashTable *static_variables = ZEND_MAP_PTR_GET(ops->static_variables_ptr);
|
||||
|
||||
if (!static_variables) {
|
||||
return;
|
||||
}
|
||||
|
||||
zend_op *opline = ops->opcodes + ops->num_args;
|
||||
|
||||
for (; opline->opcode == ZEND_BIND_STATIC; opline++) {
|
||||
if (!(opline->extended_value & (ZEND_BIND_IMPLICIT|ZEND_BIND_EXPLICIT))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Bucket *bucket = (Bucket*)
|
||||
(((char*)static_variables->arData) +
|
||||
(opline->extended_value & ~(ZEND_BIND_REF|ZEND_BIND_IMPLICIT|ZEND_BIND_EXPLICIT)));
|
||||
|
||||
if (Z_ISUNDEF(bucket->val)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
zend_hash_add_new(Z_ARRVAL_P(return_value), bucket->key, &bucket->val);
|
||||
Z_TRY_ADDREF(bucket->val);
|
||||
}
|
||||
}
|
||||
} /* }}} */
|
||||
|
||||
/* {{{ Returns a dynamically created closure for the function */
|
||||
ZEND_METHOD(ReflectionFunction, getClosure)
|
||||
{
|
||||
|
||||
@@ -50,6 +50,8 @@ abstract class ReflectionFunctionAbstract implements Reflector
|
||||
/** @return ReflectionClass|null */
|
||||
public function getClosureScopeClass() {}
|
||||
|
||||
public function getClosureUsedVariables() : array {}
|
||||
|
||||
/** @return string|false */
|
||||
public function getDocComment() {}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 0b2b52d4f891a594ccfcbcc0edeec97a9e0f80e6 */
|
||||
* Stub hash: 0e99b3dabead95a356ea4ffb16d99a3e939e9869 */
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Reflection_getModifierNames, 0, 0, 1)
|
||||
ZEND_ARG_TYPE_INFO(0, modifiers, IS_LONG, 0)
|
||||
@@ -27,6 +27,9 @@ ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_class_ReflectionFunctionAbstract_getClosureScopeClass arginfo_class_ReflectionFunctionAbstract_inNamespace
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionFunctionAbstract_getClosureUsedVariables, 0, 0, IS_ARRAY, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_class_ReflectionFunctionAbstract_getDocComment arginfo_class_ReflectionFunctionAbstract_inNamespace
|
||||
|
||||
#define arginfo_class_ReflectionFunctionAbstract_getEndLine arginfo_class_ReflectionFunctionAbstract_inNamespace
|
||||
@@ -424,8 +427,7 @@ ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_class_ReflectionNamedType_isBuiltin arginfo_class_ReflectionFunctionAbstract_inNamespace
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionUnionType_getTypes, 0, 0, IS_ARRAY, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
#define arginfo_class_ReflectionUnionType_getTypes arginfo_class_ReflectionFunctionAbstract_getClosureUsedVariables
|
||||
|
||||
#define arginfo_class_ReflectionExtension___clone arginfo_class_ReflectionFunctionAbstract___clone
|
||||
|
||||
@@ -489,7 +491,7 @@ ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_class_ReflectionAttribute_isRepeated arginfo_class_ReflectionFunctionAbstract_hasTentativeReturnType
|
||||
|
||||
#define arginfo_class_ReflectionAttribute_getArguments arginfo_class_ReflectionUnionType_getTypes
|
||||
#define arginfo_class_ReflectionAttribute_getArguments arginfo_class_ReflectionFunctionAbstract_getClosureUsedVariables
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionAttribute_newInstance, 0, 0, IS_OBJECT, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
@@ -508,7 +510,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_ReflectionEnum_getCase, 0,
|
||||
ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_class_ReflectionEnum_getCases arginfo_class_ReflectionUnionType_getTypes
|
||||
#define arginfo_class_ReflectionEnum_getCases arginfo_class_ReflectionFunctionAbstract_getClosureUsedVariables
|
||||
|
||||
#define arginfo_class_ReflectionEnum_isBacked arginfo_class_ReflectionFunctionAbstract_hasTentativeReturnType
|
||||
|
||||
@@ -557,6 +559,7 @@ ZEND_METHOD(ReflectionFunctionAbstract, isGenerator);
|
||||
ZEND_METHOD(ReflectionFunctionAbstract, isVariadic);
|
||||
ZEND_METHOD(ReflectionFunctionAbstract, getClosureThis);
|
||||
ZEND_METHOD(ReflectionFunctionAbstract, getClosureScopeClass);
|
||||
ZEND_METHOD(ReflectionFunctionAbstract, getClosureUsedVariables);
|
||||
ZEND_METHOD(ReflectionFunctionAbstract, getDocComment);
|
||||
ZEND_METHOD(ReflectionFunctionAbstract, getEndLine);
|
||||
ZEND_METHOD(ReflectionFunctionAbstract, getExtension);
|
||||
@@ -795,6 +798,7 @@ static const zend_function_entry class_ReflectionFunctionAbstract_methods[] = {
|
||||
ZEND_ME(ReflectionFunctionAbstract, isVariadic, arginfo_class_ReflectionFunctionAbstract_isVariadic, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(ReflectionFunctionAbstract, getClosureThis, arginfo_class_ReflectionFunctionAbstract_getClosureThis, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(ReflectionFunctionAbstract, getClosureScopeClass, arginfo_class_ReflectionFunctionAbstract_getClosureScopeClass, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(ReflectionFunctionAbstract, getClosureUsedVariables, arginfo_class_ReflectionFunctionAbstract_getClosureUsedVariables, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(ReflectionFunctionAbstract, getDocComment, arginfo_class_ReflectionFunctionAbstract_getDocComment, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(ReflectionFunctionAbstract, getEndLine, arginfo_class_ReflectionFunctionAbstract_getEndLine, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(ReflectionFunctionAbstract, getExtension, arginfo_class_ReflectionFunctionAbstract_getExtension, ZEND_ACC_PUBLIC)
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
--TEST--
|
||||
ReflectionFunctionAbstract::getClosureUsedVariables
|
||||
--FILE--
|
||||
<?php
|
||||
$reflector = new ReflectionFunction("strlen");
|
||||
|
||||
var_dump($reflector->getClosureUsedVariables());
|
||||
|
||||
$function = function() {
|
||||
static $one = 1;
|
||||
};
|
||||
|
||||
$reflector = new ReflectionFunction($function);
|
||||
|
||||
var_dump($reflector->getClosureUsedVariables());
|
||||
|
||||
$one = 1;
|
||||
$two = 2;
|
||||
|
||||
$function = function() use ($one, $two) {
|
||||
static $three = 3;
|
||||
};
|
||||
|
||||
$reflector = new ReflectionFunction($function);
|
||||
|
||||
var_dump($reflector->getClosureUsedVariables());
|
||||
|
||||
$function = fn() => $three = [$one];
|
||||
|
||||
$reflector = new ReflectionFunction($function);
|
||||
|
||||
var_dump($reflector->getClosureUsedVariables());
|
||||
|
||||
$function = function() use (&$one) {
|
||||
static $three = 3;
|
||||
};
|
||||
|
||||
$reflector = new ReflectionFunction($function);
|
||||
|
||||
var_dump($reflector->getClosureUsedVariables());
|
||||
?>
|
||||
--EXPECT--
|
||||
array(0) {
|
||||
}
|
||||
array(0) {
|
||||
}
|
||||
array(2) {
|
||||
["one"]=>
|
||||
int(1)
|
||||
["two"]=>
|
||||
int(2)
|
||||
}
|
||||
array(1) {
|
||||
["one"]=>
|
||||
int(1)
|
||||
}
|
||||
array(1) {
|
||||
["one"]=>
|
||||
&int(1)
|
||||
}
|
||||
Reference in new issue
Block a user