PHP 8.0: Disabled functions behave as if they do not exist

Version8.0
TypeChange

PHP has a feature to disable certain functions and classes with disable_functions and disable_classes INI directives. This is often used as a security measure to disable potentially unsafe functions.

This functionality still exists in PHP 8, but the disabled functions behave as if they are not declared at all.

Prior to PHP 8, attempting to use a disabled functions resulted in a warning:

Warning: substr() has been disabled for security reasons in ... on line ...

In PHP 8 and later, attempting to use a disabled function will throw a standard error for an undeclared function:

Fatal error: Uncaught Error: Call to undefined function substr() in ...:...

This change makes the disable feature transparent to consumers, and it even allows the function to be redefined. Prior to PHP 8, attempting to redefine a disabled function resulted in a fatal error.

disable_functions=substr
if (!function_exists('substr')) {
    function substr() {}
}
Fatal error: Cannot redeclare substr() in ... on line ...

function_exists() returns false for disabled functions

function_exists() function now returns false for functions disabled with disable_functions INI directive. This is because internally, disabled functions do not even make to the internal functions table.

Prior to PHP 8, to check if a function is disabled, one would need to query the INI setting, or use the return value of get_defined_functions() function.

Disabled functions can be redefined

In PHP 8, it is possible to redefine a disabled function.

This enables a whole new set of ways to polyfill and mock disabled function. Test frameworks and mocking frameworks will be able to dynamically disable a function, and redefine it user-land as a mock, and polyfill libraries will be able to provide a user-land implementation for functions that are disabled.

// test.php
if (function_exists('random_int')) {
    return 4;
}

If you want to mock the random_int function, now you can execute the test script with:

php -d disable_functions=random_int test.php

random_int will now always return 4 as if it was chosen by fair dice roll.

Function re-declaration and mock/polyfill exampls are covered in PHP 8: Override internal functions with disable_functions.

Deprecation notices

Related to this change, there are two new deprecation notices:

  1. ReflectionFunction::isDisabled()
  2. get_defined_functions() with $exclude_disabled has no effect

These changes are detailed in Disabled functions: Reflection and get_defined_functions() deprecations


Backwards compatibility impact

Redefining a disabled function in user-land code was not allowed in PHP versions prior to 8.0. This means you will be able to upgrade existing code, but any code that intentionally redefined a function to work-around disabled_functions feature will not work in older PHP versions.


Implementation