Table of Contents

PHP RFC: Deprecations for PHP 7.2

Introduction

This is a draft RFC for multiple deprecations targeting PHP 7.2. The RFC proposes to deprecate the listed functionality in PHP 7.2 and remove it no later than in PHP 8.0.

The following list provides a short overview of the functionality targeted for deprecation, while more detailed explanation is provided in the Proposal section:

Proposal

Each feature proposed for deprecation is voted separately. Each vote requires a 2/3 majority, independently of whether it is a language or standard library change. All votes refer to deprecation in PHP 7.2 and removal in the next major version (presumably PHP 8.0).

__autoload

The magic __autoload function has been superseded by spl_autoload_register in PHP 5.1 and its use discouraged in the documentation. One primary advantage of spl_autoload_register() is the ability to provide multiple chained autoloaders, thus easing library interoperability. Both mechanism are mutually exclusive, i.e. code using __autoload() cannot interoperate with code using spl_autoload_register(). As the latter is much more commonly used and also employed by Composer, the __autoload() mechanism has only very limited applicability nowadays.

Proposed action: A deprecation notice is thrown when a global function with name __autoload() is encountered during compilation.

Deprecate and subsequently remove __autoload
Real name Yes No
aharvey (aharvey)  
ajf (ajf)  
ashnazg (ashnazg)  
bishop (bishop)  
bwoebi (bwoebi)  
cmb (cmb)  
colinodell (colinodell)  
davey (davey)  
dm (dm)  
frozenfire (frozenfire)  
jhdxr (jhdxr)  
kalle (kalle)  
krakjoe (krakjoe)  
lcobucci (lcobucci)  
leigh (leigh)  
levim (levim)  
marcio (marcio)  
mariano (mariano)  
mbeccati (mbeccati)  
mcmic (mcmic)  
nikic (nikic)  
ocramius (ocramius)  
patrickallaert (patrickallaert)  
peehaa (peehaa)  
pierrick (pierrick)  
pollita (pollita)  
sammyk (sammyk)  
sebastian (sebastian)  
sobak (sobak)  
stas (stas)  
tpunt (tpunt)  
trowski (trowski)  
yunosh (yunosh)  
zimt (zimt)  
Final result: 33 1
This poll has been closed.

$php_errormsg

The $php_errormsg variable is created in the local scope whenever a non-fatal error is thrown, if the track_errors ini setting is enabled (disabled by default) and the error has not been consumed by an error handler.

Apart from being ini-dependent language behavior, this behavior is highly magic and the error_get_last function provides a cleaner way of retrieving the last error. Since PHP 7 additionally the error_clear_last function is available, thus covering the last possible use-cases for $php_errormsg without magic scope manipulation.

Proposed action: A deprecation notice is thrown if the track_errors ini setting is enabled.

Deprecate and subsequently remove $php_errormsg
Real name Yes No
aharvey (aharvey)  
ajf (ajf)  
ashnazg (ashnazg)  
bishop (bishop)  
bwoebi (bwoebi)  
cmb (cmb)  
colinodell (colinodell)  
davey (davey)  
frozenfire (frozenfire)  
jhdxr (jhdxr)  
kalle (kalle)  
krakjoe (krakjoe)  
lcobucci (lcobucci)  
leigh (leigh)  
levim (levim)  
marcio (marcio)  
mbeccati (mbeccati)  
mcmic (mcmic)  
nikic (nikic)  
ocramius (ocramius)  
patrickallaert (patrickallaert)  
peehaa (peehaa)  
pollita (pollita)  
sammyk (sammyk)  
sebastian (sebastian)  
stas (stas)  
tpunt (tpunt)  
trowski (trowski)  
zimt (zimt)  
Final result: 29 0
This poll has been closed.

create_function()

create_function() is a thin wrapper around the eval() language construct, allowing the creation of a function with a generated function name and the argument list and body code provided as string arguments. Before the introduction of closures in PHP 5.3 it provided a way to create something akin to lambda functions.

Due to the nature of its operation create_function(), apart from being a potential source of security issues, has very bad performance and memory usage characteristics and the use of real closures is in every way preferable.

Proposed action: Mark the function as deprecated, thus issuing a deprecation notice on every call.

Deprecate and subsequently remove create_function()
Real name Yes No
aharvey (aharvey)  
ajf (ajf)  
ashnazg (ashnazg)  
bishop (bishop)  
bwoebi (bwoebi)  
cmb (cmb)  
colinodell (colinodell)  
davey (davey)  
frozenfire (frozenfire)  
kalle (kalle)  
krakjoe (krakjoe)  
lcobucci (lcobucci)  
leigh (leigh)  
levim (levim)  
marcio (marcio)  
mbeccati (mbeccati)  
mcmic (mcmic)  
nikic (nikic)  
ocramius (ocramius)  
patrickallaert (patrickallaert)  
peehaa (peehaa)  
pollita (pollita)  
sammyk (sammyk)  
sebastian (sebastian)  
sobak (sobak)  
stas (stas)  
tpunt (tpunt)  
trowski (trowski)  
zimt (zimt)  
Final result: 29 0
This poll has been closed.

mbstring.func_overload

The mbstring.func_overload ini setting allows replacing a certain subset of string functions with analogs from the mbstring extension. For example strlen() will no longer return the length of a string in bytes, instead it will return the length in code points according to the currently selected internal encoding.

This implies that code using mbstring.func_overload is incompatible with practically all other code, which is written under the assumption that basic string operations work normally. Some libraries outright forbid func_overload (e.g. Symfony), others will break in more subtle ways. Code that wants to support func_overload needs to conditionally switch between ordinary string functions and mbstring functions with 8bit encoding (however only cryptography libraries normally bother to do this).

In a previous discussion on this topic the consensus was to deprecate this functionality. The original author of the extension also recommended this action.

Proposed action: Throw a deprecation notice if mbstring.func_overload is set to a non-zero value.

Tracking bug: #65785

Deprecate and subsequently remove mbstring.func_overload
Real name Yes No
aharvey (aharvey)  
ajf (ajf)  
ashnazg (ashnazg)  
bishop (bishop)  
bwoebi (bwoebi)  
cmb (cmb)  
davey (davey)  
frozenfire (frozenfire)  
kalle (kalle)  
krakjoe (krakjoe)  
lcobucci (lcobucci)  
leigh (leigh)  
levim (levim)  
marcio (marcio)  
mbeccati (mbeccati)  
mcmic (mcmic)  
nikic (nikic)  
ocramius (ocramius)  
patrickallaert (patrickallaert)  
peehaa (peehaa)  
pollita (pollita)  
sammyk (sammyk)  
sebastian (sebastian)  
sobak (sobak)  
stas (stas)  
tpunt (tpunt)  
trowski (trowski)  
zimt (zimt)  
Final result: 28 0
This poll has been closed.

(unset) cast

The (unset) cast casts a value to null. This means that (unset) expr is simply an expression that always returns null and has no other side effects. Apart from being useless, this behavior is also confusing, as many people reasonably assume that (unset) $a will behave similarly to unset($a), while in truth it does no such thing.

Proposed action: Throw a deprecation notice if an (unset) cast is encountered by the compiler. No deprecation notice is thrown from the lexer or parser themselves (so that token_get_all continues working as is).

Deprecate and subsequently remove (unset) cast
Real name Yes No
aharvey (aharvey)  
ajf (ajf)  
ashnazg (ashnazg)  
bishop (bishop)  
bwoebi (bwoebi)  
cmb (cmb)  
colinodell (colinodell)  
davey (davey)  
frozenfire (frozenfire)  
jhdxr (jhdxr)  
kalle (kalle)  
krakjoe (krakjoe)  
lcobucci (lcobucci)  
leigh (leigh)  
levim (levim)  
marcio (marcio)  
mbeccati (mbeccati)  
mcmic (mcmic)  
nikic (nikic)  
ocramius (ocramius)  
patrickallaert (patrickallaert)  
peehaa (peehaa)  
pollita (pollita)  
sammyk (sammyk)  
sebastian (sebastian)  
stas (stas)  
tpunt (tpunt)  
trowski (trowski)  
zimt (zimt)  
Final result: 28 1
This poll has been closed.

parse_str() without second argument

The parse_str() function is used to parse a query string either into an array if the second argument is used, or into the local symbol table if it is not used.

The second behavior is a remnant from the dark age of register_globals. It suffers from many of the same problems and presents a major security hazard if used on user-provided data.

Proposed action: Throw a deprecation notice if the second argument of parse_str() is not used.

Deprecate and subsequently remove parse_str() without second argument
Real name Yes No
aharvey (aharvey)  
ajf (ajf)  
ashnazg (ashnazg)  
bishop (bishop)  
bwoebi (bwoebi)  
cmb (cmb)  
colinodell (colinodell)  
davey (davey)  
frozenfire (frozenfire)  
kalle (kalle)  
krakjoe (krakjoe)  
lcobucci (lcobucci)  
leigh (leigh)  
levim (levim)  
marcio (marcio)  
mbeccati (mbeccati)  
mcmic (mcmic)  
nikic (nikic)  
ocramius (ocramius)  
patrickallaert (patrickallaert)  
peehaa (peehaa)  
pollita (pollita)  
sammyk (sammyk)  
sebastian (sebastian)  
sobak (sobak)  
stas (stas)  
tpunt (tpunt)  
trowski (trowski)  
zimt (zimt)  
Final result: 29 0
This poll has been closed.

gmp_random()

The gmp_random() function returns a random GMP number between 0 and 2**($n*BITS_PER_LIMB)-1, where $n is the function argument and BITS_PER_LIMB is a platform-specific parameter of the GMP/MPIR implementation that is not exposed to userland. As such, use of this function requires guessing the limb size and will likely have a platform dependence.

To remedy this PHP 5.6 introduced the gmp_random_bits() and gmp_random_range() functions, which allow precise control of the used random number range. These functions should always be preferred over gmp_random().

Proposed action: Mark the function as deprecated, thus issuing a deprecation notice on every call.

Deprecate and subsequently remove gmp_random()
Real name Yes No
aharvey (aharvey)  
ajf (ajf)  
ashnazg (ashnazg)  
bishop (bishop)  
bwoebi (bwoebi)  
cmb (cmb)  
colinodell (colinodell)  
davey (davey)  
frozenfire (frozenfire)  
kalle (kalle)  
krakjoe (krakjoe)  
lcobucci (lcobucci)  
leigh (leigh)  
levim (levim)  
marcio (marcio)  
mbeccati (mbeccati)  
mcmic (mcmic)  
nikic (nikic)  
ocramius (ocramius)  
patrickallaert (patrickallaert)  
peehaa (peehaa)  
pollita (pollita)  
sammyk (sammyk)  
sebastian (sebastian)  
tpunt (tpunt)  
trowski (trowski)  
zimt (zimt)  
Final result: 27 0
This poll has been closed.

each()

The each() function can be used to iterate over an array, similarly to using foreach. On each call, it returns an array with the current key and value and advances the internal array pointer to the next position. The typical usage, as presented in the manual, is as follows:

reset($array);
while (list($key, $val) = each($array)) {
    echo "$key => $val\n";
}

The each() function is inferior to foreach in pretty much every imaginable way, including being more than 10 times slower. The continued existence of this function poses a problem for certain language changes. For example the https://wiki.php.net/rfc/notice-for-non-valid-array-container RFC had to exclude list(), because the typical usage of each relies on the fact that you can access array offsets on false without a warning.

Proposed action: As each is typically called within loops, throwing a deprecation warning for every call is likely not advisable. Instead, throw a deprecation warning on the first call for any given request.

Deprecate and subsequently remove each()
Real name Yes No
aharvey (aharvey)  
ajf (ajf)  
ashnazg (ashnazg)  
bishop (bishop)  
bukka (bukka)  
cmb (cmb)  
davey (davey)  
kalle (kalle)  
krakjoe (krakjoe)  
lcobucci (lcobucci)  
levim (levim)  
marcio (marcio)  
mbeccati (mbeccati)  
nikic (nikic)  
ocramius (ocramius)  
patrickallaert (patrickallaert)  
peehaa (peehaa)  
pollita (pollita)  
sammyk (sammyk)  
sebastian (sebastian)  
stas (stas)  
tpunt (tpunt)  
trowski (trowski)  
zimt (zimt)  
Final result: 18 6
This poll has been closed.

assert() with string argument

The assert() function has two modes of operation: If it is passed something other than a string, it will assert that the value is truthy. If a string is passed, it will be run through eval() and assert will check that the result of the eval() is truthy.

The reason for this behavior is that prior to PHP 7 this was the only way to prevent the assertion expression from evaluating. As of PHP 7, the zend.assertions ini option can be used to avoid evaluation of assertion expressions. As such, there is no longer a need for supporting implicitly evaluated string arguments.

This behavior of assert() makes it easy to introduce subtle remote code execution vulnerabilities. Using assert($value) to check if a value is truthy opens an RCE vulnerability if there is any chance for $value to be a string.

Proposed action: Throw a deprecation notice if assert() is used with a string argument. The deprecation notice is only thrown if assertions are enabled (both zend.assertions and assert.active must be enabled).

Deprecate and subsequently remove assert() with string argument
Real name Yes No
aharvey (aharvey)  
ajf (ajf)  
ashnazg (ashnazg)  
bishop (bishop)  
colinodell (colinodell)  
davey (davey)  
frozenfire (frozenfire)  
jhdxr (jhdxr)  
kalle (kalle)  
krakjoe (krakjoe)  
lcobucci (lcobucci)  
leigh (leigh)  
levim (levim)  
marcio (marcio)  
mbeccati (mbeccati)  
mcmic (mcmic)  
nikic (nikic)  
ocramius (ocramius)  
peehaa (peehaa)  
pollita (pollita)  
sammyk (sammyk)  
sebastian (sebastian)  
stas (stas)  
tpunt (tpunt)  
trowski (trowski)  
zimt (zimt)  
Final result: 25 1
This poll has been closed.

$errcontext argument of error handler

Error handlers set with set_error_handler() are passed an $errcontext as the last argument. This argument is an array containing all local variables at the point the error was generated.

This functionality is problematic for optimization, because the $errcontext can be used to modify all references and objects in the current scope. As far as I am aware, this functionality is barely used and the trade-off here is not worthwhile. If people wish to inspect the variable-state at the point of an error, they should use a proper debugger.

Note that the error context only contains the local variables at the error-site. The error backtrace, including $this and function arguments, will of course stay available through debug_backtrace().

Proposed action: Throw deprecation notice if error handler has five or more arguments. Otherwise, do not pass the $errcontext. This prevents circumvention with func_get_args().

Update: Due to technical issues, this does not throw a deprecation warning. It is a documentation-only deprecation.

Deprecate and subsequently remove $errcontext argument of error handler
Real name Yes No
aharvey (aharvey)  
ajf (ajf)  
ashnazg (ashnazg)  
bishop (bishop)  
bwoebi (bwoebi)  
cmb (cmb)  
davey (davey)  
frozenfire (frozenfire)  
kalle (kalle)  
krakjoe (krakjoe)  
lcobucci (lcobucci)  
leigh (leigh)  
levim (levim)  
marcio (marcio)  
mbeccati (mbeccati)  
nikic (nikic)  
ocramius (ocramius)  
peehaa (peehaa)  
pollita (pollita)  
sammyk (sammyk)  
sebastian (sebastian)  
stas (stas)  
tpunt (tpunt)  
trowski (trowski)  
zimt (zimt)  
Final result: 22 3
This poll has been closed.

(binary) cast and b"" literals

This deprecation has been extracted into a separate RFC: Binary String Deprecation RFC

Backward Incompatible Changes

For PHP 7.2 additional deprecation notices will appear. For PHP 8.0 the previously deprecated functionality will no longer be available.

Proposed Voting Choices

Each of the bullet points above will get a separate vote. All votes will require a 2/3 supermajority, independently of whether they are language changes or not.

Patches and Tests

The patches for these deprecations are for the most part trivial, as such they will be provided once the RFC is accepted (or portions of it).

Suggested deprecations

The following list contains various suggested deprecations that may or may not be included in this RFC (TODO section).

Rejected deprecations

The following section lists features that have been suggested for deprecation, but have not been included in this RFC for the outlined reasons.

$http_response_header

The $http_response_header variable is created in the local scope if an HTTP request is performed, for example through file_get_contents(). It contains an array of HTTP response headers.

The motivations for removing this functionality are similar to those of $php_errormsg, so it would seem reasonable to deprecate them at the same time. However, unlike $php_errormsg there exist no simple alternatives to $http_response_header. The get_headers function returns only the headers, but not the response body. Getting both requires, to my knowledge, a combination of fopen(), stream_get_contents() and reading the wrapper_data from stream_get_meta_data().