summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2020-04-27 13:17:37 +0200
committerNikita Popov <nikita.ppv@gmail.com>2020-04-30 09:53:57 +0200
commit53eee290b6f5ca531aef19885a392c939013ce36 (patch)
tree1eac8e854e60f39bd3432f92a603f9f0b9d41169
parent8cb237345a50f724aca35133da7155b6bc47d133 (diff)
downloadphp-git-53eee290b6f5ca531aef19885a392c939013ce36.tar.gz
Completely remove disabled functions from function table
Currently, disabling a function only replaces the internal function handler with one that throws a warning, and a few places in the engine special-case such functions, such as function_exists. This leaves us with a Schrödinger's function, which both does not exist (function_exists returns false) and does exist (you cannot define a function with the same name). In particular, this prevents the implementation of robust polyfills, as reported in https://bugs.php.net/bug.php?id=79382: if (!function_exists('getallheaders')) { function getallheaders(...) { ... } } If getallheaders() is a disabled function, this code will break. This patch changes disable_functions to remove the functions from the function table completely. For all intents and purposes, it will look like the function does not exist. This also renders two bits of PHP functionality obsolete and thus deprecated: * ReflectionFunction::isDisabled(), as it will no longer be possible to construct the ReflectionFunction of a disabled function in the first place. * get_defined_functions() with $exclude_disabled=false, as get_defined_functions() now never returns disabled functions. Fixed bug #79382. Closes GH-5473.
-rw-r--r--UPGRADING13
-rw-r--r--Zend/tests/bug69315.phpt64
-rw-r--r--Zend/tests/bug79382.phpt18
-rw-r--r--Zend/tests/errmsg_020.phpt12
-rw-r--r--Zend/zend_API.c20
-rw-r--r--Zend/zend_API.h2
-rw-r--r--Zend/zend_builtin_functions.c30
-rw-r--r--Zend/zend_builtin_functions.stub.php2
-rw-r--r--Zend/zend_builtin_functions_arginfo.h2
-rw-r--r--Zend/zend_compile.c4
-rw-r--r--ext/opcache/Optimizer/pass1.c20
-rw-r--r--ext/opcache/Optimizer/sccp.c3
-rw-r--r--ext/opcache/Optimizer/zend_func_info.c4
-rw-r--r--ext/opcache/Optimizer/zend_optimizer.c7
-rw-r--r--ext/opcache/Optimizer/zend_optimizer_internal.h1
-rw-r--r--ext/opcache/tests/bug68104.phpt13
-rw-r--r--ext/opcache/tests/bug76796.phpt11
-rw-r--r--ext/reflection/php_reflection.c8
-rw-r--r--ext/reflection/php_reflection.stub.php5
-rw-r--r--ext/reflection/php_reflection_arginfo.h2
-rw-r--r--ext/reflection/tests/ReflectionFunction_isDisabled_basic.phpt18
-rw-r--r--tests/basic/bug31875.phpt10
22 files changed, 139 insertions, 130 deletions
diff --git a/UPGRADING b/UPGRADING
index de376fec44..96b9745d4c 100644
--- a/UPGRADING
+++ b/UPGRADING
@@ -178,6 +178,9 @@ PHP 8.0 UPGRADE NOTES
}
RFC: https://wiki.php.net/rfc/abstract_trait_method_validation
+ . Disabled functions are now treated exactly like non-existent functions.
+ Calling a disabled function will report it as unknown, and redefining a
+ disabled function is now possible.
- COM:
. Removed the ability to import case-insensitive constants from type
@@ -500,6 +503,11 @@ PHP 8.0 UPGRADE NOTES
4. Deprecated Functionality
========================================
+- Core:
+ . Calling get_defined_functions() with $exclude_disabled explicitly set to
+ false is deprecated. get_defined_functions() will never include disabled
+ functions.
+
- Enchant:
. enchant_broker_set_dict_path and enchant_broker_get_dict_path
not available in libenchant < 1.5 nor in libenchant-2
@@ -511,6 +519,11 @@ PHP 8.0 UPGRADE NOTES
do not accept empty files as valid zip archives any longer.
Existing workaround will be removed in next version.
+- Reflection:
+ . ReflectionFunction::isDisabled() is deprecated, as it is no longer possible
+ to create a ReflectionFunction for a disabled function. This method now
+ always returns false.
+
========================================
5. Changed Functions
========================================
diff --git a/Zend/tests/bug69315.phpt b/Zend/tests/bug69315.phpt
index 0eb5afb080..82017c0552 100644
--- a/Zend/tests/bug69315.phpt
+++ b/Zend/tests/bug69315.phpt
@@ -7,32 +7,44 @@ disable_functions=strlen,defined,call_user_func,constant,is_string
var_dump(function_exists("strlen"));
var_dump(is_callable("strlen"));
-var_dump(strlen("xxx"));
-var_dump(defined("PHP_VERSION"));
-var_dump(constant("PHP_VERSION"));
-var_dump(call_user_func("strlen"));
-var_dump(is_string("xxx"));
-var_dump(is_string());
+try {
+ var_dump(strlen("xxx"));
+} catch (Error $e) {
+ echo $e->getMessage(), "\n";
+}
+try {
+ var_dump(defined("PHP_VERSION"));
+} catch (Error $e) {
+ echo $e->getMessage(), "\n";
+}
+try {
+ var_dump(constant("PHP_VERSION"));
+} catch (Error $e) {
+ echo $e->getMessage(), "\n";
+}
+try {
+ var_dump(call_user_func("strlen"));
+} catch (Error $e) {
+ echo $e->getMessage(), "\n";
+}
+try {
+ var_dump(is_string("xxx"));
+} catch (Error $e) {
+ echo $e->getMessage(), "\n";
+}
+try {
+ var_dump(is_string());
+} catch (Error $e) {
+ echo $e->getMessage(), "\n";
+}
?>
---EXPECTF--
+--EXPECT--
bool(false)
-bool(true)
-
-Warning: strlen() has been disabled for security reasons in %sbug69315.php on line %d
-NULL
-
-Warning: defined() has been disabled for security reasons in %sbug69315.php on line %d
-NULL
-
-Warning: constant() has been disabled for security reasons in %sbug69315.php on line %d
-NULL
-
-Warning: call_user_func() has been disabled for security reasons in %sbug69315.php on line %d
-NULL
-
-Warning: is_string() has been disabled for security reasons in %sbug69315.php on line %d
-NULL
-
-Warning: is_string() has been disabled for security reasons in %s on line %d
-NULL
+bool(false)
+Call to undefined function strlen()
+Call to undefined function defined()
+Call to undefined function constant()
+Call to undefined function call_user_func()
+Call to undefined function is_string()
+Call to undefined function is_string()
diff --git a/Zend/tests/bug79382.phpt b/Zend/tests/bug79382.phpt
new file mode 100644
index 0000000000..bc6099c4e4
--- /dev/null
+++ b/Zend/tests/bug79382.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Bug #79382: Cannot redeclare disabled function
+--INI--
+disable_functions=strlen
+--FILE--
+<?php
+
+function strlen(string $x): int {
+ $len = 0;
+ while (isset($x[$len])) $len++;
+ return $len;
+}
+
+var_dump(strlen("foobar"));
+
+?>
+--EXPECT--
+int(6)
diff --git a/Zend/tests/errmsg_020.phpt b/Zend/tests/errmsg_020.phpt
index 636e29d01f..4a7c326d05 100644
--- a/Zend/tests/errmsg_020.phpt
+++ b/Zend/tests/errmsg_020.phpt
@@ -5,10 +5,12 @@ disable_functions=phpinfo
--FILE--
<?php
-phpinfo();
+try {
+ phpinfo();
+} catch (Error $e) {
+ echo $e->getMessage(), "\n";
+}
-echo "Done\n";
?>
---EXPECTF--
-Warning: phpinfo() has been disabled for security reasons in %s on line %d
-Done
+--EXPECT--
+Call to undefined function phpinfo()
diff --git a/Zend/zend_API.c b/Zend/zend_API.c
index 37c8820164..d2fb08d2d9 100644
--- a/Zend/zend_API.c
+++ b/Zend/zend_API.c
@@ -2686,27 +2686,9 @@ ZEND_API int zend_set_hash_symbol(zval *symbol, const char *name, int name_lengt
/* Disabled functions support */
-/* {{{ proto void display_disabled_function(void)
-Dummy function which displays an error when a disabled function is called. */
-ZEND_API ZEND_COLD ZEND_FUNCTION(display_disabled_function)
-{
- zend_error(E_WARNING, "%s() has been disabled for security reasons", get_active_function_name());
-}
-/* }}} */
-
ZEND_API int zend_disable_function(char *function_name, size_t function_name_length) /* {{{ */
{
- zend_internal_function *func;
- if ((func = zend_hash_str_find_ptr(CG(function_table), function_name, function_name_length))) {
- zend_free_internal_arg_info(func);
- func->fn_flags &= ~(ZEND_ACC_VARIADIC | ZEND_ACC_HAS_TYPE_HINTS | ZEND_ACC_HAS_RETURN_TYPE);
- func->num_args = 0;
- func->required_num_args = 0;
- func->arg_info = NULL;
- func->handler = ZEND_FN(display_disabled_function);
- return SUCCESS;
- }
- return FAILURE;
+ return zend_hash_str_del(CG(function_table), function_name, function_name_length);
}
/* }}} */
diff --git a/Zend/zend_API.h b/Zend/zend_API.h
index 51353ad710..fe6ec000e9 100644
--- a/Zend/zend_API.h
+++ b/Zend/zend_API.h
@@ -593,8 +593,6 @@ ZEND_API zend_bool zend_is_iterable(zval *iterable);
ZEND_API zend_bool zend_is_countable(zval *countable);
-ZEND_API ZEND_FUNCTION(display_disabled_function);
-
ZEND_API int zend_get_default_from_internal_arg_info(
zval *default_value_zval, zend_internal_arg_info *arg_info);
diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c
index 5682d02822..300adf400e 100644
--- a/Zend/zend_builtin_functions.c
+++ b/Zend/zend_builtin_functions.c
@@ -1127,7 +1127,7 @@ ZEND_FUNCTION(trait_exists)
ZEND_FUNCTION(function_exists)
{
zend_string *name;
- zend_function *func;
+ zend_bool exists;
zend_string *lcname;
ZEND_PARSE_PARAMETERS_START(1, 1)
@@ -1142,15 +1142,10 @@ ZEND_FUNCTION(function_exists)
lcname = zend_string_tolower(name);
}
- func = zend_hash_find_ptr(EG(function_table), lcname);
+ exists = zend_hash_exists(EG(function_table), lcname);
zend_string_release_ex(lcname, 0);
- /*
- * A bit of a hack, but not a bad one: we see if the handler of the function
- * is actually one that displays "function is disabled" message.
- */
- RETURN_BOOL(func && (func->type != ZEND_INTERNAL_FUNCTION ||
- func->internal_function.handler != zif_display_disabled_function));
+ RETURN_BOOL(exists);
}
/* }}} */
@@ -1420,30 +1415,25 @@ ZEND_FUNCTION(get_defined_functions)
zval internal, user;
zend_string *key;
zend_function *func;
- zend_bool exclude_disabled = 0;
- char *disable_functions = NULL;
+ zend_bool exclude_disabled = 1;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &exclude_disabled) == FAILURE) {
RETURN_THROWS();
}
+ if (exclude_disabled == 0) {
+ zend_error(E_DEPRECATED,
+ "get_defined_functions(): Setting $exclude_disabled to false has no effect");
+ }
+
array_init(&internal);
array_init(&user);
array_init(return_value);
- if (exclude_disabled) {
- disable_functions = INI_STR("disable_functions");
- }
ZEND_HASH_FOREACH_STR_KEY_PTR(EG(function_table), key, func) {
if (key && ZSTR_VAL(key)[0] != 0) {
if (func->type == ZEND_INTERNAL_FUNCTION) {
- if (disable_functions != NULL) {
- if (strstr(disable_functions, func->common.function_name->val) == NULL) {
- add_next_index_str(&internal, zend_string_copy(key));
- }
- } else {
- add_next_index_str(&internal, zend_string_copy(key));
- }
+ add_next_index_str(&internal, zend_string_copy(key));
} else if (func->type == ZEND_USER_FUNCTION) {
add_next_index_str(&user, zend_string_copy(key));
}
diff --git a/Zend/zend_builtin_functions.stub.php b/Zend/zend_builtin_functions.stub.php
index ec3d5a5203..43b55b42a7 100644
--- a/Zend/zend_builtin_functions.stub.php
+++ b/Zend/zend_builtin_functions.stub.php
@@ -85,7 +85,7 @@ function get_declared_traits(): array {}
function get_declared_interfaces(): array {}
-function get_defined_functions(bool $exclude_disabled = false): array {}
+function get_defined_functions(bool $exclude_disabled = true): array {}
function get_defined_vars(): array {}
diff --git a/Zend/zend_builtin_functions_arginfo.h b/Zend/zend_builtin_functions_arginfo.h
index ab4510f3d8..571b14ba72 100644
--- a/Zend/zend_builtin_functions_arginfo.h
+++ b/Zend/zend_builtin_functions_arginfo.h
@@ -146,7 +146,7 @@ ZEND_END_ARG_INFO()
#define arginfo_get_declared_interfaces arginfo_func_get_args
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_get_defined_functions, 0, 0, IS_ARRAY, 0)
- ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, exclude_disabled, _IS_BOOL, 0, "false")
+ ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, exclude_disabled, _IS_BOOL, 0, "true")
ZEND_END_ARG_INFO()
#define arginfo_get_defined_vars arginfo_func_get_args
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index 0923aa7141..bc214fa39a 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -3934,10 +3934,6 @@ int zend_compile_func_array_slice(znode *result, zend_ast_list *args) /* {{{ */
int zend_try_compile_special_func(znode *result, zend_string *lcname, zend_ast_list *args, zend_function *fbc, uint32_t type) /* {{{ */
{
- if (fbc->internal_function.handler == ZEND_FN(display_disabled_function)) {
- return FAILURE;
- }
-
if (CG(compiler_options) & ZEND_COMPILE_NO_BUILTINS) {
return FAILURE;
}
diff --git a/ext/opcache/Optimizer/pass1.c b/ext/opcache/Optimizer/pass1.c
index 9219e5e19e..3beb1788a3 100644
--- a/ext/opcache/Optimizer/pass1.c
+++ b/ext/opcache/Optimizer/pass1.c
@@ -382,12 +382,10 @@ constant_binary_op:
Z_TYPE(ZEND_OP1_LITERAL(send1_opline)) == IS_STRING) {
if ((Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("function_exists")-1 &&
!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
- "function_exists", sizeof("function_exists")-1) &&
- !zend_optimizer_is_disabled_func("function_exists", sizeof("function_exists") - 1)) ||
+ "function_exists", sizeof("function_exists")-1)) ||
(Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("is_callable")-1 &&
!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
- "is_callable", sizeof("is_callable")) &&
- !zend_optimizer_is_disabled_func("is_callable", sizeof("is_callable") - 1))) {
+ "is_callable", sizeof("is_callable")))) {
zend_internal_function *func;
zend_string *lc_name = zend_string_tolower(
Z_STR(ZEND_OP1_LITERAL(send1_opline)));
@@ -400,12 +398,7 @@ constant_binary_op:
#endif
) {
zval t;
- if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("is_callable") - 1 ||
- func->handler != ZEND_FN(display_disabled_function)) {
- ZVAL_TRUE(&t);
- } else {
- ZVAL_FALSE(&t);
- }
+ ZVAL_TRUE(&t);
literal_dtor(&ZEND_OP2_LITERAL(init_opline));
MAKE_NOP(init_opline);
literal_dtor(&ZEND_OP1_LITERAL(send1_opline));
@@ -423,8 +416,7 @@ constant_binary_op:
break;
} else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("extension_loaded")-1 &&
!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
- "extension_loaded", sizeof("extension_loaded")-1) &&
- !zend_optimizer_is_disabled_func("extension_loaded", sizeof("extension_loaded") - 1)) {
+ "extension_loaded", sizeof("extension_loaded")-1)) {
zval t;
zend_string *lc_name = zend_string_tolower(
Z_STR(ZEND_OP1_LITERAL(send1_opline)));
@@ -465,8 +457,7 @@ constant_binary_op:
break;
} else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("constant")-1 &&
!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
- "constant", sizeof("constant")-1) &&
- !zend_optimizer_is_disabled_func("constant", sizeof("constant") - 1)) {
+ "constant", sizeof("constant")-1)) {
zval t;
if (zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(send1_opline)), &t, 1)) {
@@ -488,7 +479,6 @@ constant_binary_op:
} else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("dirname")-1 &&
!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)),
"dirname", sizeof("dirname") - 1) &&
- !zend_optimizer_is_disabled_func("dirname", sizeof("dirname") - 1) &&
IS_ABSOLUTE_PATH(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)))) {
zend_string *dirname = zend_string_init(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)), 0);
ZSTR_LEN(dirname) = zend_dirname(ZSTR_VAL(dirname), ZSTR_LEN(dirname));
diff --git a/ext/opcache/Optimizer/sccp.c b/ext/opcache/Optimizer/sccp.c
index d5c27ca664..adea218778 100644
--- a/ext/opcache/Optimizer/sccp.c
+++ b/ext/opcache/Optimizer/sccp.c
@@ -1019,8 +1019,7 @@ static inline int ct_eval_func_call(
}
func = zend_hash_find_ptr(CG(function_table), name);
- if (!func || func->type != ZEND_INTERNAL_FUNCTION
- || func->internal_function.handler == ZEND_FN(display_disabled_function)) {
+ if (!func || func->type != ZEND_INTERNAL_FUNCTION) {
return FAILURE;
}
diff --git a/ext/opcache/Optimizer/zend_func_info.c b/ext/opcache/Optimizer/zend_func_info.c
index 6f1c247051..ff29cce989 100644
--- a/ext/opcache/Optimizer/zend_func_info.c
+++ b/ext/opcache/Optimizer/zend_func_info.c
@@ -899,9 +899,7 @@ static uint32_t get_internal_func_info(
}
func_info_t *info = Z_PTR_P(zv);
- if (UNEXPECTED(zend_optimizer_is_disabled_func(info->name, info->name_len))) {
- return MAY_BE_NULL;
- } else if (info->info_func) {
+ if (info->info_func) {
return info->info_func(call_info, ssa);
} else {
return info->info;
diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c
index 6f896af27c..61d2750ce9 100644
--- a/ext/opcache/Optimizer/zend_optimizer.c
+++ b/ext/opcache/Optimizer/zend_optimizer.c
@@ -157,13 +157,6 @@ static inline int zend_optimizer_add_literal_string(zend_op_array *op_array, zen
return zend_optimizer_add_literal(op_array, &zv);
}
-int zend_optimizer_is_disabled_func(const char *name, size_t len) {
- zend_function *fbc = (zend_function *)zend_hash_str_find_ptr(EG(function_table), name, len);
-
- return (fbc && fbc->type == ZEND_INTERNAL_FUNCTION &&
- fbc->internal_function.handler == ZEND_FN(display_disabled_function));
-}
-
static inline void drop_leading_backslash(zval *val) {
if (Z_STRVAL_P(val)[0] == '\\') {
zend_string *str = zend_string_init(Z_STRVAL_P(val) + 1, Z_STRLEN_P(val) - 1, 0);
diff --git a/ext/opcache/Optimizer/zend_optimizer_internal.h b/ext/opcache/Optimizer/zend_optimizer_internal.h
index ed0dac3e19..a525b668bf 100644
--- a/ext/opcache/Optimizer/zend_optimizer_internal.h
+++ b/ext/opcache/Optimizer/zend_optimizer_internal.h
@@ -108,7 +108,6 @@ void zend_optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_c
void zend_optimizer_nop_removal(zend_op_array *op_array, zend_optimizer_ctx *ctx);
void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx *ctx);
void zend_optimizer_compact_vars(zend_op_array *op_array);
-int zend_optimizer_is_disabled_func(const char *name, size_t len);
zend_function *zend_optimizer_get_called_func(
zend_script *script, zend_op_array *op_array, zend_op *opline, zend_bool *is_prototype);
uint32_t zend_optimizer_classify_function(zend_string *name, uint32_t num_args);
diff --git a/ext/opcache/tests/bug68104.phpt b/ext/opcache/tests/bug68104.phpt
index 8d3bf70a4d..6d994c79af 100644
--- a/ext/opcache/tests/bug68104.phpt
+++ b/ext/opcache/tests/bug68104.phpt
@@ -11,9 +11,12 @@ disable_functions=dl
--FILE--
<?php
var_dump(is_callable("dl"));
-dl("a.so");
+try {
+ dl("a.so");
+} catch (Error $e) {
+ echo $e->getMessage(), "\n";
+}
?>
---EXPECTF--
-bool(true)
-
-Warning: dl() has been disabled for security reasons in %sbug68104.php on line %d
+--EXPECT--
+bool(false)
+Call to undefined function dl()
diff --git a/ext/opcache/tests/bug76796.phpt b/ext/opcache/tests/bug76796.phpt
index ba7e26a0d5..18f25d2558 100644
--- a/ext/opcache/tests/bug76796.phpt
+++ b/ext/opcache/tests/bug76796.phpt
@@ -10,9 +10,12 @@ disable_functions=strpos
--FILE--
<?php
-var_dump(strpos('foo', 'bar'));
+try {
+ var_dump(strpos('foo', 'bar'));
+} catch (Error $e) {
+ echo $e->getMessage(), "\n";
+}
?>
---EXPECTF--
-Warning: strpos() has been disabled for security reasons in %s on line %d
-NULL
+--EXPECT--
+Call to undefined function strpos()
diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c
index 552913dd1e..2856e0c6db 100644
--- a/ext/reflection/php_reflection.c
+++ b/ext/reflection/php_reflection.c
@@ -1549,16 +1549,12 @@ ZEND_METHOD(ReflectionFunctionAbstract, isUserDefined)
Returns whether this function has been disabled or not */
ZEND_METHOD(ReflectionFunction, isDisabled)
{
- reflection_object *intern;
- zend_function *fptr;
-
- GET_REFLECTION_OBJECT_PTR(fptr);
-
if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}
- RETURN_BOOL(fptr->type == ZEND_INTERNAL_FUNCTION && fptr->internal_function.handler == zif_display_disabled_function);
+ /* A disabled function cannot be queried using Reflection. */
+ RETURN_FALSE;
}
/* }}} */
diff --git a/ext/reflection/php_reflection.stub.php b/ext/reflection/php_reflection.stub.php
index be6269fe78..0adce7921c 100644
--- a/ext/reflection/php_reflection.stub.php
+++ b/ext/reflection/php_reflection.stub.php
@@ -104,7 +104,10 @@ class ReflectionFunction extends ReflectionFunctionAbstract
public function __toString(): string {}
- /** @return bool */
+ /**
+ * @return bool
+ * @deprecated ReflectionFunction can no longer be constructed for disabled functions
+ */
public function isDisabled() {}
/** @return mixed */
diff --git a/ext/reflection/php_reflection_arginfo.h b/ext/reflection/php_reflection_arginfo.h
index a0a606295b..a7f12dba8c 100644
--- a/ext/reflection/php_reflection_arginfo.h
+++ b/ext/reflection/php_reflection_arginfo.h
@@ -694,7 +694,7 @@ static const zend_function_entry class_ReflectionFunctionAbstract_methods[] = {
static const zend_function_entry class_ReflectionFunction_methods[] = {
ZEND_ME(ReflectionFunction, __construct, arginfo_class_ReflectionFunction___construct, ZEND_ACC_PUBLIC)
ZEND_ME(ReflectionFunction, __toString, arginfo_class_ReflectionFunction___toString, ZEND_ACC_PUBLIC)
- ZEND_ME(ReflectionFunction, isDisabled, arginfo_class_ReflectionFunction_isDisabled, ZEND_ACC_PUBLIC)
+ ZEND_ME(ReflectionFunction, isDisabled, arginfo_class_ReflectionFunction_isDisabled, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED)
ZEND_ME(ReflectionFunction, invoke, arginfo_class_ReflectionFunction_invoke, ZEND_ACC_PUBLIC)
ZEND_ME(ReflectionFunction, invokeArgs, arginfo_class_ReflectionFunction_invokeArgs, ZEND_ACC_PUBLIC)
ZEND_ME(ReflectionFunction, getClosure, arginfo_class_ReflectionFunction_getClosure, ZEND_ACC_PUBLIC)
diff --git a/ext/reflection/tests/ReflectionFunction_isDisabled_basic.phpt b/ext/reflection/tests/ReflectionFunction_isDisabled_basic.phpt
index 220c16f9cb..d634927516 100644
--- a/ext/reflection/tests/ReflectionFunction_isDisabled_basic.phpt
+++ b/ext/reflection/tests/ReflectionFunction_isDisabled_basic.phpt
@@ -7,8 +7,18 @@ TestFest PHP|Tek
disable_functions=is_file
--FILE--
<?php
-$rc = new ReflectionFunction('is_file');
-var_dump($rc->isDisabled());
+try {
+ $rf = new ReflectionFunction('is_file');
+ var_dump($rf->isDisabled());
+} catch (ReflectionException $e) {
+ echo $e->getMessage(), "\n";
+}
+
+$rf = new ReflectionFunction('is_string');
+var_dump($rf->isDisabled());
?>
---EXPECT--
-bool(true)
+--EXPECTF--
+Function is_file() does not exist
+
+Deprecated: Function ReflectionFunction::isDisabled() is deprecated in %s on line %d
+bool(false)
diff --git a/tests/basic/bug31875.phpt b/tests/basic/bug31875.phpt
index 65f68b9af3..c8ad25ec9f 100644
--- a/tests/basic/bug31875.phpt
+++ b/tests/basic/bug31875.phpt
@@ -8,6 +8,8 @@ disable_functions=dl
<?php
$disabled_function = 'dl';
+/* exclude_disabled parameters is harded to true */
+
$functions = get_defined_functions();
var_dump(in_array($disabled_function, $functions['internal']));
@@ -17,7 +19,9 @@ var_dump(in_array($disabled_function, $functions['internal']));
$functions = get_defined_functions(true);
var_dump(in_array($disabled_function, $functions['internal']));
?>
---EXPECT--
-bool(true)
-bool(true)
+--EXPECTF--
+bool(false)
+
+Deprecated: get_defined_functions(): Setting $exclude_disabled to false has no effect in %s on line %d
+bool(false)
bool(false)