rfc:deprecations_php_8_6

PHP RFC: Deprecations for PHP 8.6

Introduction

The RFC proposes to deprecate the listed functionality in PHP 8.6 and remove it in PHP 9 (except where otherwise noted).

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

  • Deprecate the list() construct
  • Deprecate returning from a finally block
  • Deprecate using certain names as identifiers to reserve them as keywords
    • Deprecate using “let” as an identifier
    • Deprecate using “namespace” as a class constant or static property name
    • Deprecate using “in”, “out”, and “inout” as identifiers
    • Deprecate using “is” as an identifier
    • Deprecate the possibility to name a function “readonly”
    • Deprecate using “_” as a constant and compile time alias
    • Deprecate using “_” as a function name and the _() function alias for gettext()
  • Passing objects which are interpreted as arrays
    • Passing objects for $array parameter of array_walk() and array_walk_recursive()
    • Passing objects for $options parameter of deflate_init() and inflate_init()
    • Passing objects as parameters to the zlib.inflate and zlib.deflate stream filters
    • Passing objects as parameters to the bzip2.decompress and bzip2.compress stream filters
    • Passing objects for $vars parameter of mb_convert_variables()
    • Passing objects for $data parameter of http_build_query()
  • Deprecate function aliases with non-canonical type name
  • Deprecate define() with $case_insensitive being specified
  • Deprecate is_subclass_of with string when $allow_string is false
  • Deprecate is_a with string when $allow_string is false
  • Deprecate strcoll()
  • Deprecate SORT_LOCALE_STRING flag for sort() functions
  • Deprecate metaphone function
  • Deprecate dechunk filter
  • Deprecate ReflectionProperty::setValue() and ReflectionProperty::setRawValue() with wrong types
  • Deprecate ReflectionMethod::invoke() and ReflectionMethod::invokeArgs() with objects for static methods
  • Deprecate ArrayIterator methods that inherit ArrayObject implementation
  • Deprecate spl_classes()
  • Deprecate spl_object_hash
  • Deprecate SplFileObject CSV methods
  • Deprecate mysqli::stmt_init()
  • Deprecate mysqli_get_charset()
  • Deprecate passing a $sessionhandler object to session_set_save_handler() which does not contain the create_sid() and validateId() methods

Proposal

Each feature proposed for deprecation is voted separately and requires a 2/3 majority. All votes refer to deprecation in PHP 8.6 and removal in PHP 9 (except where otherwise noted).

Deprecate the list() construct

The list() construct destructures an array into individual variables. It may appear only on the left-hand side of an assignment or as the target of a foreach:

list($a, $b) = [1, 2];
 
foreach ($pairs as list($key, $value)) {
    // ...
}

Since PHP 7.1, the short syntax [$a, $b] does exactly the same thing in exactly the same positions, with identical semantics for nesting, skipped elements, and keyed destructuring:

[$a, $b] = [1, 2];
 
foreach ($pairs as [$key, $value]) {
    // ...
}

The two forms are interchangeable. list() adds no capability the short syntax lacks; it is a longer spelling of the same operation, kept only for backward compatibility. Having two ways to write the same destructuring is a cost with no return: it is more for newcomers to learn, more for tooling to special-case, and a recurring source of “which one should I use” with no real answer.

The name itself is misleading. Set next to array("a" => $a, "b" => $b), the construct list($a, $b) reads as though it builds some kind of list value, a sibling of array(). It does no such thing. It constructs nothing; it pulls values out of an existing array and binds them to variables. The name implies creation where the operation is the exact opposite, which is precisely backwards for someone meeting it for the first time.

list() also looks like a function call but is not one. It cannot be assigned to a variable, passed as a callable, or used anywhere other than the two assignment positions above. Despite this, it occupies the list keyword, which therefore cannot be used as a function name, or class-like name. Reclaiming it would free list for ordinary use, or leave it available should a future list type ever be proposed.

This proposal adds a deprecation at compile time wherever the list() construct is used. The short array syntax is unaffected, runtime behaviour does not change, and every existing use can be rewritten mechanically by replacing list(...) with [...].

The goal is removal in the next major version, freeing the list keyword entirely.

Migration is automatable. The entire transformation can be applied across a codebase with a single command:

ast-grep run --pattern 'list($$$ARGS)' --rewrite '[$$$ARGS]' --lang php -U

Other tools such as Rector can perform the same migration.

If accepted, use of the list() construct emits the following deprecation notice at compile time.

Deprecated: The list() construct is deprecated, use [...] instead

Impact analysis: Deprecate the list() construct: 12.275 occurrences in 5.545 files Full details: https://gist.github.com/jrfnl/9ca4af66f31c5afd08a4598ae73c0ded

Deprecate the list() construct?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Deprecate returning from a finally block

When a try or catch block is exiting by throwing an exception or returning a value, a return inside the finally silently discards it. The exception is swallowed, or the return value is overwritten, and the function hands its caller a normal-looking result. Nothing records that a failure occurred. No error, no warning, no notice, no trace.

function getConfig(): array {
    try {
        return loadConfig(); // throws if the file is missing
    } finally {
        return []; // the exception is gone, the caller just gets []
    }
}

The silence is the problem. The failure does not merely change a result. It vanishes, and if it resurfaces at all it does so far from the finally and long after, as a wrong value, an empty result, or an action that quietly never happened, with nothing pointing back to its cause. A discarded exception is exactly the kind of failure a language should make visible rather than swallow without a word.

A static scan of the ~5000 most-installed Composer packages found a return inside a finally in 12 places across 9 packages. Reading each one, 9 are deliberate or harmless, and in 3 the try can throw on a real path whose exception the finally return would discard.

Returning from a finally is never the only way to express a result. The same outcome can always be written without it, so no capability is lost. Runtime behaviour does not change. The language raises nothing for this construct today, and this proposal adds a deprecation at compile time wherever a finally contains a return, so the pattern is caught while the code is being written, before it silently swallows an exception in production.

If accepted, a return inside a finally block emits the following deprecation notice at compile time.

Deprecated: Returning from a finally block is deprecated

Impact analysis: Deprecate return from finally: 8 occurrences Full details: https://gist.github.com/jrfnl/7902d86aa5d6b306e0edad9d7c1ff274

Deprecate returning from a finally block?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Deprecate using certain names as identifiers to reserve them as keywords

We propose deprecating using certain names as identifiers, i.e. function, constant, class, interface, trait, or enum names, to reserve them as keywords for potential future PHP features.

Deprecate using "let" as an identifier

The motivation for this deprecation is to properly reserve this identifier as a potential keyword for PHP. It was previously proposed as part of the let construct (Block Scoping) RFC, which was not accepted. Nevertheless let is the obvious keyword for block scoping and reserving it now allows a possible future block scoping RFC to use the keyword without a breaking change.

The analysis performed at part of the let construct (Block Scoping) RFC indicated an insignificant usage of “let” in the wild.

If accepted, calling a class, interface, trait, enum, constant, or function “let” will emit a deprecation

Deprecated: Calling a {class|trait|interface|enum|constant|function} “let” is deprecated

If accepted, using “let” as a value for the second argument of class_alias() ($alias) will emit a deprecation:

Deprecated: class_alias: Passing “let” as value to argument #2 ($alias) is deprecated

Impact analysis: Deprecate identifier “let”: 3 occurrences Full details: https://gist.github.com/jrfnl/e540ce964e348d5ab6ebf07937763173

Deprecate using let as an identifier?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Deprecate using "namespace" as a class constant or static property name

namespace” is currently a semi-reserved keyword, which makes it allowed to be used as a class member name. The proposal is to deprecate the usage of namespace as a constant and static property name, to later promote it to a fully reserved keyword.

class Foo {
  const NAMESPACE = '';  // deprecated
  static $namespace = ''; // deprecated
}

The motivation is to reserve namespace for future syntax. In particular, it would allow a future ::namespace pseudo-constant, analogous to ::class, for directory namespaces (eg. to replace stringy APIs like “Order\\Domain\\Entities” with \Order\Domain\Entities::namespace for better IDE support). Methods named “namespace”, such as Route::namespace(), are not affected.

A search on GitHub yields ~120 matching files. Affected code can migrate by renaming the member to a name like NAMESPACE_NAME.

If accepted, declaring such member will emit a deprecation:

Deprecated: Declaring {class|interface|trait|enum} {constant|static property} “namespace” is deprecated

Impact analysis: Deprecate namespace as class constant or static property: 21 occurrences Full details: https://gist.github.com/jrfnl/a23b568f7b99775a1a3434e7176ced48

Deprecate using namespace as a class constant or static property name?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Deprecate using "in", "out", and "inout" as identifiers

The motivation for this deprecation is to properly reserve those words as potential keywords for PHP. These keywords may form the basis of a better way to deal with references in PHP, namely regarding type consistency and mutability. These keywords may also be used as part of co/contra-variance indications for generic types; this observation comes from the secondary vote of the "Bound-Erased Generic Types" RFC about what type of variance marker syntax should be adopted.

If accepted, calling a class, interface, trait, enum, constant, or function “in”, “out”, or “inout” will emit a deprecation:

Deprecated: Calling a {class|trait|interface|enum|constant|function} “{in|out|inout}” is deprecated

If accepted, using “in”, “out”, or “inout” as a value for the second argument of class_alias() ($alias) will emit a deprecation:

Deprecated: class_alias: Passing “{in|out|inout}” as value to argument #2 ($alias) is deprecated

Impact analysis: Deprecate identifiers in/out/inout: 33 occurrences. in: 25 (includes Doctrine, Laminas, Laravel and Magento), out: 8, inout: 0 Full details: https://gist.github.com/jrfnl/9c1430200757daa529b5f9b667585b10

Deprecate using in, out, and inout as identifiers?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Deprecate using "is" as an identifier

The motivation for this deprecation is to properly reserve this identifier for the pattern matching RFC.

If accepted, calling a class, interface, trait, enum, constant, or function “is” will emit a deprecation

Deprecated: Calling a {class|trait|interface|enum|constant|function} “is” is deprecated

If accepted, using “is” as a value for the second argument of class_alias() ($alias) will emit a deprecation:

Deprecated: class_alias: Passing “is” as value to argument #2 ($alias) is deprecated

If accepted, using “is” as an alias name in a use declaration will emit a compile time deprecation:

Deprecated: using “is” as a class name is deprecated

Impact analysis: Deprecate identifier “is”: 9 occurrences Full details: https://gist.github.com/jrfnl/49ee0a1b863d56e85b8b4b18bbcc79c9

Deprecate using is as an identifier?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Deprecate the possibility to name a function "readonly"

readonly is nominally a reserved keyword for PHP. However, late in the development cycle of PHP 8.1 it was identified that WordPress has a function named “readonly”; as such we introduced a lexer “hack” to allow this. 1) This needed to be changed with the introduction of DNF types. 2)

This is a rather odd situation of a keyword being allowed in a specific circumstance when no other keyword in PHP is able to do so.

As such we propose deprecating using “readonly” as a function name.

If accepted, calling a function “readonly” will emit a deprecation:

Deprecated: Calling a function “readonly” is deprecated

Impact analysis: Deprecate identifier readonly as function: 2 occurrences Full details: https://gist.github.com/jrfnl/fb680994d2d6f99c36e68a710fc2740d

Deprecate the possibility to name a function readonly?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Deprecate using "_" as a constant and compile time alias

Back in PHP 8.4 naming a class/interface/trait/enum "_" (single underscore) was deprecated so that it could potentially be used as a potential wildcard pattern for the pattern matching RFC.

We propose to extend this deprecation to constants, so that this reserved identifier follows the same rule as most other identifiers in PHP. Moreover, in the initial deprecation we missed the fact that a compile time alias use MyClass as _; could be used to alias a class to the “_” name.

If accepted, calling a constant “_” will emit a deprecation:

Deprecated: Calling a constant “_” is deprecated

If accepted, using “_” as an alias name in a use declaration will emit a compile time deprecation:

Deprecated: using “_” as a class name is deprecated

Impact analysis: Deprecate _ as constant/compile time alias: 7 occurrences Full details: https://gist.github.com/jrfnl/f7ad1aad5842187e44c16be2f34ad9eb

Deprecate using _ as a constant and compile time alias?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Deprecate using "_" as a function name and the _() function alias for gettext()

The primary motivation for this deprecation is to make “_” a reserved keyword, as indicated by one of the previous deprecation proposals. To match the semantics of other keywords in PHP this means deprecating the use of “_” as a function name. However, the gettext extension provides a function named “_” and to be fully coherent it would need to also be deprecated. Luckily, the _() function is an alias for the gettext() function and both have existed since PHP 4. Therefore, we deem the impact of deprecating this function alias to be relatively low as the function calls can be renamed on virtually any PHP codebase in existence with various PHP userland or system tools.

If accepted, calling a function “_” will emit a deprecation:

Deprecated: Calling a function “_” is deprecated

If accepted, calling the _() function will emit the following deprecation:

Deprecated: The _() function is deprecated, use gettext() instead

Impact analysis: Deprecate _ as function name and the _() function: 4 + 96 occurrences Full details: https://gist.github.com/jrfnl/f7ad1aad5842187e44c16be2f34ad9eb https://gist.github.com/jrfnl/bf2b5fb4ef1f836db2d8d84ee4828dc2

Deprecate using _ as a function name and the _() function alias for gettext()?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Passing objects which are interpreted as arrays

A limited amount of PHP functions and features permit passing an object rather than an array and have it be interpreted as an array of the visible properties. This is done via the HASH_OF internal macro, the A and H ZPP specifiers, or one of the Z_PARAM_ARRAY_OR_OBJECT* fast ZPP macros.

Current functions and features utilising this capability which aren't already deprecated are:

For nearly all of these cases, instead of passing an object one can simply call get_object_vars() on the object prior to passing it to the function/stream context.

There are a few motivations for removing this ability from the engine. Primarily it has to do with semantics; modifying such a HashTable (the internal representation of an array) violates readonly semantics, and can corrupt enum cases. However, even if not modifying, care must be taken when dealing with HashTables resulting from objects, as they may include indirect zvals which refer to properties. We have had multiple bugs due to the lack of handling indirect properties, partly due to lack of testing. Finally, the ability to pass objects to a small number of functions and features seems to rarely be known about.

Passing objects for $array parameter of array_walk() and array_walk_recursive()

Other than the reasons previously explained as to why it would be beneficial to deprecate this behaviour, array_walk_recursive() will not recursively walk through objects, only arrays. As such an instance of a class:

class Foo {
    public array $array;
    public Foo $innerFoo;
    public string $str;
}

will not walk through the properties of the $innerFoo object.

As explained previously, if the callback provided takes the argument by reference, then it is possible to modify the value and violate readonly semantics.

Therefore we propose to deprecate passing objects for the $array parameter of array_walk() and array_walk_recursive()

If accepted, calling array_walk() or array_walk_recursive() with an object will emit a deprecation notice:

Deprecated: Passing an object for argument #1 $array to array_walk{_recursive}() is deprecated, call get_object_vars() first instead

Passing objects for $array parameter of array_walk() and array_walk_recursive()?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Passing objects for $options parameter of deflate_init() and inflate_init()

The motivation has been detailed above, and this is a relatively unknown feature. Therefore, we propose to deprecate passing an object for the $option argument to inflate_init() and deflate_init().

If accepted, calling inflate_init() or deflate_init() with an object will emit a deprecation notice:

Deprecated: Passing an object for argument #2 $option to {in|de}flate_init() is deprecated, call get_object_vars() first instead

Passing objects for $options parameter of deflate_init() and inflate_init()?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Passing objects as parameters to the ''zlib.inflate'' and ''zlib.deflate'' stream filters

Stream filter parameters can be set via the stream_filter_prepend() or stream_filter_append() and are validated in the filter creation factory method. However we cannot prevent passing objects to stream_filter_prepend() or stream_filter_append() as a user stream filter may expect an object as a parameter. Therefore we propose to check in the php_zlib_filter_create() C function that the filter parameters, if provided, are of type array, or for zlib.deflate it may also be of type int. Especially as the PHP documentation only mentions the possibility to pass the parameters as an associative array.

If accepted, attempting to set an object as filter parameters for the zlib.inflate and zlib.deflate stream filters will emit a deprecation notice:

Deprecated: Passing an object for filter parameters for zlib.{de|in}flate is deprecated, call get_object_vars() first instead

Passing objects as parameters to the zlib.inflate and zlib.deflate stream filters?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Passing objects as parameters to the ''bzip2.decompress'' and ''bzip2.compress'' stream filters

Stream filter parameters can be set via the stream_filter_prepend() or stream_filter_append() and are validated in the filter creation factory method. However we cannot prevent passing objects to stream_filter_prepend() or stream_filter_append() as a user stream filter may expect an object as a parameter. Therefore we propose to check in the php_bz2_filter_create() C function that the filter parameters, if provided, are of type array. Especially as the PHP documentation only mentions the possibility to pass the parameters as an associative array.

If accepted, attempting to set an object as filter parameters for the bzip2.decompress and bzip2.compress stream filters will emit a deprecation notice:

Deprecated: Passing an object for filter parameters for bzip2.{de}compress is deprecated, call get_object_vars() first instead

Passing objects as parameters to the bzip2.decompress and bzip2.compress stream filters?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Passing objects for $vars parameter of mb_convert_variables()

The motivation has been detailed above, and this is a relatively unknown feature. Therefore, we propose to deprecate passing an object for the $vars argument to mb_convert_variables(). Moreover, this function is extremely weird in that it takes the variable by reference to modify it in-place. The same behaviour can be achieved using the mb_convert_encoding() function in a cleaner and more intuitive way, as it also permits arrays that are converted recursively.

If accepted, calling mb_convert_variables() with an object will emit a deprecation notice:

Deprecated: Passing an object for argument #3 $vars to mb_convert_variables() is deprecated, call get_object_vars() first instead

As future scope it may be worthwhile to deprecate this function altogether in favour of mb_convert_encoding().

Passing objects for $vars parameter of mb_convert_variables()?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Passing objects for $data parameter of http_build_query()

The motivation has been detailed above, however in this case the feature is somewhat known and well documented in the manual. Thus it might be the most controversial deprecation of the lot. Ideally the Query Params RFC would have been finalised for PHP 8.6 as it would be a great alternative to this function.

However, the fact objects are treated like arrays has caused confusion and bug reports, namely regarding Stringable objects, as users expect them to get cast to a string rather than being used as an array. 3)4)

While the argument that object properties satisfy a key-value relationship (which is what this function cares about) and thus are perfectly suitable for this case, the confusion around this behaviour, the impossibility to support stringable objects in a non BC-breaking manner, and the rarity of the ability to use objects as an array we propose to deprecate this behaviour in favour of calling get_object_vars() (possibly recursively) on the objects and pass an associative array instead.

Objects encountered while traversing will also emit a deprecation notice prompting users to pre-process the array to use get_object_vars() on such values. This can be achieved with the following function:

function convert_obj_to_arr_rec(mixed $v)
{
    if (is_array($v)) {
        return array_map(convert_obj_to_arr_rec(...), $v);
    } else if (is_object($v)) {
        return array_map(convert_obj_to_arr_rec(...), get_object_vars($v));
    }
    return $v;
}

If accepted, calling http_build_query() with an object will emit a deprecation notice:

Deprecated: Passing an object for argument #1 $data to http_build_query() is deprecated, call get_object_vars() first instead

And if an object is encountered during traversal the following deprecatioin will be emitted:

Deprecated: object values within argument #1 $data to http_build_query() being interpreted as arrays is deprecated, instead the $data argument should be preprocessed with get_object_vars()

As a future scope, we may want to mark the php_url_encode_hash_ex() C API as static instead of exposing it, as a SourceGraph query shows basically no usage. 5)

Passing objects for $data parameter of http_build_query()?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Deprecate function aliases with non-canonical type name

Following the deprecation of non-standard cast names in PHP 8.5, it is consistent to consider deprecating legacy aliases which preserve the same non-canonical type terminology.

The following proposals aim to deprecate using “integer” or “long” as aliases for the int type and using “double” as an alias for the float type.

These names originate from historical internal naming and platform-specific integer sizing, but it no longer communicates anything useful to userland code. Keeping those aliases offers no functional value and keeps outdated terminology alive.

Deprecate is_double()

is_double() is a legacy alias of is_float(). Modern PHP presents the scalar type as float, and the canonical predicate is is_float().

This proposal deprecates is_double() and recommends using is_float() instead.

if (is_double($value)) {
    // ...
}
// To:
if (is_float($value)) {
    // ...
}

If accepted, calling is_double() will emit a deprecation notice:

Deprecated: Function is_double() is deprecated, use is_float() instead

Impact analysis: Deprecate is_double(): 35 occurrences Full details: https://gist.github.com/jrfnl/e646412ca381ea0feca27604e713af0b

Deprecate is_double()?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Deprecate is_integer()

is_integer() is a legacy alias of is_int(). Modern PHP presents the scalar type as int, and the canonical predicate is is_int().

This proposal deprecates is_integer() and recommends using is_int() instead.

if (is_integer($value)) {
    // ...
}
// To:
if (is_int($value)) {
    // ...
}

If accepted, calling is_integer() will emit a deprecation notice:

Deprecated: Function is_integer() is deprecated, use is_int() instead

Impact analysis: Deprecate is_integer(): 303 occurrences Full details: https://gist.github.com/jrfnl/90cede1a93ddb217123c5ff9e6b3dbb6

Deprecate is_integer()?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Deprecate is_long()

is_long() is a legacy alias of is_int(). Modern PHP presents the scalar type as int, and the canonical predicate is is_int().

This proposal deprecates is_long() and recommends using is_int() instead.

if (is_long($value)) {
    // ...
}
// To:
if (is_int($value)) {
    // ...
}

If accepted, calling is_long() will emit a deprecation notice:

Deprecated: Function is_long() is deprecated, use is_int() instead

Impact analysis: Deprecate is_long(): 16 occurrences Full details: https://gist.github.com/jrfnl/27b7b20240c6ebc2a227130d0367d108

Deprecate is_long()?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Deprecate doubleval()

doubleval() is a legacy alias of floatval(). Since floatval() is the canonical function name and matches the scalar type name float, keeping doubleval() provides no distinct behavior and only increases the number of ways to express the same conversion.

This proposal deprecates doubleval() and recommends using floatval() instead.

$number = doubleval($value);
// To:
$number = floatval($value);

If accepted, calling doubleval() will emit a deprecation notice:

Deprecated: Function doubleval() is deprecated, use floatval() instead

Impact analysis: Deprecate doubleval(): 8 occurrences Full details: https://gist.github.com/jrfnl/c6df988ab223d0e905e4d6c9a18da8cc

Deprecate doubleval()?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Deprecate define() with $case_insensitive being specified

In PHP 7.3, case-insensitive constants were deprecated, see PHP RFC: Deprecate and Remove Case-Insensitive Constants. The implementation of the deprecation included E_DEPRECATED alerts when trying to define case insensitive constants.

However, when support was removed in PHP 8.0, the deprecation message was replaced with a E_WARNING rather than triggering an error. We propose to convert the warning to an error in PHP 9.0. In PHP 8.6 and until PHP 9.0, the E_WARNING code level will be kept (since warnings are considered stronger than deprecations) but the message will be updated to indicate that it will be upgraded to throwing an error in the future.

If accepted, the message will be:

Warning: define(): Argument #3 ($case_insensitive) is ignored since declaration of case-insensitive constants is no longer supported, this will be an error in PHP 9.0.

To avoid the confusing case of a parameter still existing but only being allowed to be false, we also propose to deprecate explicitly passing in the value false (until 9.0) at which point the value can be removed entirely. If false is manually specified, a new E_DEPRECATION will be emitted:

Deprecated: Argument #3 ($case_insensitive) is ignored and treated as false since declaration of case-insensitive constants is no longer supported, passing the argument explicitly is unnecessary.

Impact analysis: Deprecate define() $case_insensitive: 42 occurrences Full details: https://gist.github.com/jrfnl/610c5c0c21f1ff45d1932ba1f49bf621

Since the default has always been that the value is false, there are not backwards compatibility concerns about callers needing to provide false on previous versions.

Deprecate define() with $case_insensitive being specified?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Deprecate is_subclass_of with string when $allow_string is false

is_subclass_of is used to check if an object or class name is a subclass of some other named class/interface. The first parameter can be either an object to check, or the name of a class. The third parameter, $allow_string, controls whether the first parameter can be a string. The reason this is useful is that when set to false, strings will not trigger autoloading. However, if a string is given when $allow_string is false, the function will always return false, even if the class does not need to be autoloaded.

If a developer has specified that strings should not be allowed (the default is that they are allowed), then passing strings indicates a bug. We propose to deprecate providing a string to the first parameter if strings are not allowed. This will be bumped to an error in PHP 9.0.

If accepted, calling is_subclass_of with a string but strings not being allowed will emit the following deprecation

Deprecated: Calling is_subclass_of() with a string but with $allow_string = false is deprecated, if the class should not be autoloaded check class_exists() and then call is_subclass_of() with $allow_string = true if the class is already loaded.

Impact analysis: Deprecate is_subclass_of() with string and $allow_string false: 0 occurrences Full details: https://gist.github.com/jrfnl/6c95a9b2408bee1a1e85e1629de6a2fd

Deprecate is_subclass_of with string when $allow_string is false?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Deprecate is_a with string when $allow_string is false

is_a is used to check if an object or class name is an instance of some other named class/interface. The first parameter can be either an object to check, or the name of a class. The third parameter, $allow_string, controls whether the first parameter can be a string. The reason this is useful is that when set to false, strings will not trigger autoloading. However, if a string is given when $allow_string is false, the function will always return false, even if the class does not need to be autoloaded.

If a developer has specified that strings should not be allowed (the default is that they are allowed), then passing strings indicates a bug. We propose to deprecate providing a string to the first parameter if strings are not allowed. This will be bumped to an error in PHP 9.0.

If accepted, calling is_subclass_of with a string but strings not being allowed will emit the following deprecation

Deprecated: Calling is_a() with a string but with $allow_string = false is deprecated, if the class should not be autoloaded check class_exists() and then call is_a() with $allow_string = true if the class is already loaded.

Impact analysis: Deprecate is_a() with string and $allow_string false: 0 occurrences Full details: https://gist.github.com/jrfnl/17c0dc1d402ea97eec887a96b117f9be

Deprecate is_a with string when $allow_string is false?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Deprecate strcoll()

The strcoll() function permits comparing two strings depending on the current LC_COLLATE setting set via setlocale(). Because setlocale() relies on global state that can be set by any application/library running on the system it is generally discouraged to rely on it. Moreover, some locales may not necessarily properly implement the collation rules to sort strings in different natural languages/locales as can be seen by a user note on the strcoll() documentation from 2019.

This function is also not binary safe, meaning if the string contains a null byte, the string will be truncated and discard anything past the null byte. While this shouldn't happen in practice, all other string comparison functions are binary safe.

Finally, the intl extension provides a direct replacement which is more accurate and has up-to-date sorting rules via the Collator::compare() method.

Therefore, we propose to deprecate the strcoll() function and recommand using Collator::compare() instead.

If accepted, calling strcoll() will emit a deprecation notice:

Deprecated: Function strcoll() is deprecated, use Collator::compare() instead

Impact analysis: Deprecate strcoll(): 11 occurrences Full details: https://gist.github.com/jrfnl/28c192b1f2a1fa1ae06b9df9646c1da5

Deprecate strcoll()?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Deprecate SORT_LOCALE_STRING flag for sort() functions

This flag sorts an array using the strcoll() function. The same problems that strcoll() has also apply to this flag: relying on global state, not binary safe, may sort incorrectly. And like strcoll() it has alternatives provided by the intl extension, which are:

  • Collator::sort()
  • Collator::asort()
  • Collator::sort()
  • Collator::sortWithSortKeys()

As such, we propose deprecating the SORT_LOCALE_STRING constant in favour of one of the listed Collator methods.

If accepted, using the SORT_LOCALE_STRING constant will emit a deprecation notice:

Deprecated: Constant SORT_LOCALE_STRING is deprecated, use one of the Collator::*sort*() methods instead

Impact analysis: Deprecate SORT_LOCALE_STRING: 17 occurrences Full details: https://gist.github.com/jrfnl/3ef53816ec959e53a7d86b6dbb1f900e

Deprecate SORT_LOCALE_STRING flag for sort() functions?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Deprecate Metaphone Function

The metaphone() function calculates the metaphone key of a string. The original Metaphone algorithm was published in 1990. However, it has significant limitations:

  • It is strictly limited to English pronunciation rules.
  • It has been superseded by more accurate algorithms, namely Double Metaphone (1999) and Metaphone 3 (2009).

Currently, PHP core maintains the oldest and least accurate version of this algorithm in C. Since phonetic algorithms are language-specific and frequently updated, they are better suited for userland implementation. There are already robust and actively maintained userland libraries available via Composer that implement Double Metaphone and Metaphone 3. [1][2]

Maintaining this legacy function in the core provides little value to modern PHP applications, and therefore we propose to deprecate metaphone() in PHP 8.6.

Note: For the same reason, it is also reasonable to deprecate soundex. However, soundex is widely supported by SQL databases so its deprecation might cause a bigger impact.

The implementation is already done at: https://github.com/php/php-src/pull/21889

Impact analysis: Deprecate metaphone(): 9 occurrences Full details: https://gist.github.com/jrfnl/cc0221a1de954b6c7fa8d26da3fbab28

Deprecate Metaphone Function?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Deprecate dechunk filter

The dechunk stream filter is an undocumented feature in PHP designed to decode HTTP chunked transfer encoding. While it is utilized internally by PHP's HTTP stream wrapper, its exposure to userland (particularly through ''php://filter'') has become a notorious vector for security exploits.

This proposal seeks to deprecate the dechunk filter for userland usage in PHP 8.6 to eliminate a high-risk attack surface.

The dechunk filter is heavily abused in filter chain attacks to create error-based side-channel oracles. Because it interprets strings based on whether they start with a valid hexadecimal character, attackers use it to exfiltrate local files blindly. The filter is undocumented in the official PHP manual. Furthermore, its implementation is historically loose, skipping non-hex characters arbitrarily to find chunk extensions. HTTP chunk decoding is easy to implement in userland PHP for the occasions it is required outside of standard HTTP clients.

Being undocumented puts it in a limbo state of being a filter that is available but not fully supported. Deprecating it would solve this.

This proposal proposes to fully deprecate the dechunk filter. There was some discussion on the mailing list to deprecate it only for use in php://filter, but still allow use in stream_filter_append. This would keep the limbo state of a partially supported function, and increase the inconsistency in that some filters can be used in some contexts but not in others.

While the filter is largely unknown to everyday developers, it does have existing usage:

  • PHP's HTTP stream wrapper relies on this filter internally when handling Transfer-Encoding: chunked. This will remain as-is and will not be deprecated.
  • Some userland libraries explicitly invoke it via stream filter functions, such as Symfony's HttpClient, php-http/message DechunkStream. These will need an alternative, such as decoding it using code written in PHP.

There is currently no clear upgrade path with built-in PHP functions. There is no PHP function that does chunked message decoding. Libraries would need to implement the decoding in PHP. If they register a filter that does the decoding, it is possible that filter can also be used in filter chain attacks, just like the native dechunk filter.

An alternative upgrade path is to depend on curl or URL fopen wrappers to perform HTTP requests, instead of decoding responses in PHP.

The proposal is to deprecate the filter entirely for all userland calls (both php://filter and stream_filter_append()), keeping it strictly as an unexposed internal mechanism for the HTTP stream wrapper.

Deprecated: The “dechunk” stream filter is deprecated and will be removed in a future version of PHP.

References:

Deprecate dechunk filter?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Deprecate ReflectionProperty::setValue() and ReflectionProperty::setRawValue() with wrong types

ReflectionProperty methods are used to interact with the representation of a property on a class. For example, ReflectionProperty::getValue() can only be called with an object that is either an instance of the target class, or a subclass thereof (i.e. any object that actually has the property).

However, ReflectionProperty::setValue() and ReflectionProperty::setRawValue() do not validate what type of object they are given. For example, the following code works fine:

<?php
 
class Foo {
    private mixed $value;
}
 
#[AllowDynamicProperties]
class Bar {}
 
$reflection = new ReflectionProperty(Foo::class, 'value');
$obj = new Bar();
$reflection->setValue($obj, true);
 
var_dump($obj);

this sets a new property named “value” on the instance of the Bar class, even though the Bar class is entirely unrelated to the Foo class. If the property does not already exist on the target object, it is no better than using a normal assignment; if it does already exist on the target object, it will be set, but it is still conceptually wrong because despite the reflection being about “a Foo::class property named $value” the property set will be unrelated to the Foo class.

This lack of validation differs from other ReflectionProperty methods, which generally throw exceptions when given an object that is not an instance of the class the property was declared in, e.g. getValue(), getRawValue(), isInitialized(), isReadable(), and isWritable().

Accordingly, we propose to emit deprecation warnings when ReflectionProperty::setValue() and ReflectionProperty::setRawValue() are used with objects that are not instances of the class that the property corresponds to. Doing so will emit a deprecation warning, similar to:

Deprecated: Calling ReflectionProperty::setValue() with a given object that is not an instance of the class this property was declared in is deprecated.

with the appropriate adjustment for ReflectionProperty::setRawValue().

Deprecate ReflectionProperty::setValue() and ReflectionProperty::setRawValue() with wrong types?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Deprecate ReflectionMethod::invoke() and ReflectionMethod::invokeArgs() with objects for static methods

ReflectionMethod::invoke() (and ReflectionMethod::invokeArgs()) are used to invoke a method even if it is not normally accessible to the calling scope due to visibility restrictions. They both accept as the first parameter an optional object. When invoking a non-static method, that object is required, and is used as the value of $this for the method call. However, for static methods, the parameter is ignored entirely, even when provided (since static methods do not have a $this context).

When invoking static methods, the provided object is not validated in any way - it can be any object (or null). It can be an instance of an entirely different class; for non-static methods, this would trigger an exception, but for static methods it is silently ignored.

Rather than adding validation for the object being a valid instance of the method's class, given that the object is entirely unused we propose to deprecate passing any object to ReflectionMethod::invoke() and ReflectionMethod::invokeArgs() when invoking static methods.

The deprecation warning would be similar to:

Deprecated: ReflectionMethod::invoke() for a static method does not need an object parameter.

with the appropriate adjustment for ReflectionMethod::invokeArgs().

Deprecate ReflectionMethod::invoke() and ReflectionMethod::invokeArgs() with objects for static methods?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Deprecate ArrayIterator methods that inherit ArrayObject implementation

Various ArrayIterator methods only exist because for a long time it shared a common implementation with ArrayObject. Most of these methods do not make much sense, and prevent optimizing the implementation of ArrayIterator.

We propose deprecating the following methods:

Those methods would NOT be deprecated from ArrayObject.

Deprecate ArrayIterator methods that inherit ArrayObject implementation?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Deprecate spl_classes()

This function returns a list of all classes and interfaces that are part of the SPL extension. Since 2008, the Reflection extension has always been available, and using that extension should be preferred over this function that no other extensions expose. Use ReflectionExtension::getClassNames() instead.

If accepted, calling the function will emit the following deprecation

Deprecated: Function spl_classes() is deprecated since 8.6, use ReflectionExtension::getClassNames() instead.

Impact analysis: Deprecate spl_classes(): 0 occurrences Full details: https://gist.github.com/jrfnl/8a0231930956a66e7c4f316dd44c515c

Deprecate spl_classes()?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Deprecate spl_object_hash()

The spl_object_hash() function returns a unique identifier for an object. However, the “hash” part is a bit of a misnomer since it is not based on the contents of an object. Since PHP 7.2, spl_object_id() has been available that also returns a unique id, but as an integer and with a clearer function name.

Since PHP 8.1, the semantic content from spl_object_hash() and spl_object_id() has been exactly the same; the former is merely a reformatted representation of the latter.

The spl_object_hash() manual page observes that when comparing hashes it is important to use strict equality because, for example, “00000000000000e70000000000000000” == “00000000000000e60000000000000000” evaluates to true: both are interpreted as numeric strings (representing floats equalling 0.0). This extends to other comparisons (e.g., switch, in_array()). (Another mitigation would be to prepend a non-numeric prefix.)

If you need an identifier in the format that spl_object_hash() returns, code such as the following two examples can be written:

str_pad(dechex(spl_object_id($obj)), 16, '0', STR_PAD_LEFT) . '0000000000000000'   sprintf(32, "%016x0000000000000000", spl_object_id($obj))

Accordingly, we propose to deprecate spl_object_hash(). If accepted, calling the method will emit the following deprecation:

Deprecated: Function spl_object_hash() is deprecated since 8.6, consider using spl_object_id() instead.

Impact analysis: Deprecate spl_object_hash(): 625 occurrences Full details: https://gist.github.com/jrfnl/6ff4e1316d58b98e15f82d1ce33a565d

Deprecate spl_object_hash()?
Real name
Final result:
This poll has been closed.

Deprecate SplFileObject CSV methods

* Author: Muhammed Arshid arshidkv12@gmail.com

The following methods of SplFileObject are proposed for deprecation:

* SplFileObject::fgetcsv() * SplFileObject::fputcsv() * SplFileObject::setCsvControl() * SplFileObject::getCsvControl()

These APIs have become increasingly difficult to maintain due to historical design issues and inconsistencies. The introduction of named arguments has further exposed problems in the API design and behavior.

CSV processing functionality does not naturally belong in SplFileObject, and future work would be better served by a dedicated CSV extension providing a cleaner and more maintainable API.

Deprecate SplFileObject CSV methods?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Deprecate mysqli::stmt_init

  • Author: Kamil Tekiela

This function creates an empty mysqli_stmt object that still needs to be prepared before use. There is no justified reason for this function to exist. It is the source of many ways in which mysqli objects can be left in an inconsistent state. It looks like it is only used in PHP unit tests. It's not used in any popular open-source project. Since this function doesn't provide any tangible value and leads to confusing code, it should be removed to reduce language complexity.

$stmt = $mysqli->stmt_init();
$stmt->prepare($sql);
// To:
$stmt = $mysqli->prepare($sql);

If accepted, calling mysqli::stmt_init() will emit a deprecation notice:

Deprecated: Method mysqli::stmt_init() is deprecated, use mysqli::prepare() instead

The procedural style function mysqli_stmt_init() will also be deprecated:

Deprecated: Function mysqli_stmt_init() is deprecated, use mysqli_prepare() instead

An alternative and almost unknown way of calling this function is through the constructor, which is equally useless. This proposal includes the deprecation of this feature, i.e. calling mysqli_stmt::__construct without the second argument.

$stmt = new mysqli_stmt($mysqli);
$stmt->prepare($sql);
// To:
$stmt = new mysqli_stmt($mysqli, $sql);

If accepted, calling new mysqli_stmt() without the second argument will emit a deprecation notice:

Deprecated: Instantiation of mysqli_stmt without providing the $query parameter is deprecated

Impact analysis: Deprecate mysqli_stmt_init() (scanned for procedural calls only): 0 occurrences Full details: https://gist.github.com/jrfnl/8dff0f35070a13ab4dd3d6e03acb6874

Deprecate mysqli::stmt_init, mysqli_stmt_init, and mysqli_stmt::__construct without the second argument?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Deprecate mysqli_get_charset()

  • Author: Kamil Tekiela

This function can be used to retrieve internal implementation details of the currently selected character set. It was able to provide more meaningful values when mysqli was compiled against libmysql, but since PHP 8.2 that's no longer the case. The values reported are:

  • Character set name. The same as is returned by mysqli_character_set_name()
  • Default collation name for that charset as defined by mysqlnd, not by the server. As this information doesn't correspond to the true values defined by the server it is of no use to anyone.
  • Directory from which the charset information was imported. Used only with libmysql for dynamically loaded character sets. In mysqlnd it's an empty string.
  • Minimum and maximum character length of the character set. This is the only truly useful and correct information provided by this function, but it is still an implementation detail and in my opinion, not something that a PHP user would ever need to know.
  • Collation ID as defined by mysqlnd. It's just a number. It cannot be used for anything as it's not guaranteed that it's the same as defined in MySQL/MariaDB. As of PHP 8.6, it is set to 0 in all cases. Even in libmysql it's no longer used, other than for finding out the default collation of a charset for backwards compatibility reasons.
  • State. In libmysql it is always the value 1. In libmysql it was a bitflag of internal characteristics of the character set. It has no use in PHP.

The proposal is to deprecate and remove this function, and its OO-style alias mysqli::get_charset(), and later remove it without a substitute. It's pretty unlikely that any PHP project still uses this function, and if they do, they probably don't know that it returns falsified information. The only uses I was able to find (see the user comment in PHP manual) are people incorrectly assuming that it returns the currently set collation. By removing this function, we reduce one more point of confusion for PHP users.

If accepted, calling mysqli_get_charset() will emit a deprecation notice:

Deprecated: Function mysqli_get_charset() is deprecated, did you mean mysqli_character_set_name()?

Impact analysis: Deprecate mysqli_get_charset(): 0 occurrences Full details: https://gist.github.com/jrfnl/d3358fee835bd75ed25b23be46541a91

The reason for this message is that mysqli_get_charset seems like a logical antonym to mysqli_set_charset and people wanting to know the name of currently selected character set should use mysqli_character_set_name

Deprecate mysqli_get_charset()?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Deprecate passing a $sessionhandler object to session_set_save_handler() which does not contain the create_sid() and validateId() methods

User-defined session handlers aren't forced to implement methods that would ensure that the session extension is well behaved in regards to the session.use_strict_mode INI setting. This is important as the default value for it has been changed in the "Secure Session Configuration Defaults" RFC, and should never be disabled.

The methods which are required for the behaviour to be well-defined are create_sid() and validateId().

The proposal is effectively integrating the SessionIdInterface interface and the validateId() method from the SessionUpdateTimestampHandlerInterface interface into the SessionHandlerInterface interface.

Therefore, we propose to emit a deprecation when calling session_set_save_handler() with an object that doesn't implement the create_sid() and validateId() methods, regardless of whether it implements either SessionIdInterface or SessionUpdateTimestampHandlerInterface. But we also propose to emit a warning when implementing the SessionHandlerInterface interface on a class which doesn't define the create_sid() or validateId() methods.

If accepted, calling session_set_save_handler() with an object that doesn't implement the create_sid() and validateId() methods will emit the following deprecation:

Deprecated: Providing an object to argument #1 ($sessionhandler) which does not have the {create_sid|validateId}() method defined is deprecated

And the following warning will be emitted when implementing SessionHandlerInterface on a class which doesn't define the create_sid() or validateId() methods:

Warning: Interface SessionHandlerInterface will require the {create_sid|validateId}() method in PHP 9.0

In PHP 9 the validateId() method would be removed from SessionUpdateTimestampHandlerInterface.

As a future scope, during the PHP 9 release cycle one could deprecate the SessionIdInterface interface as it effectively becomes useless.

Deprecate passing a $sessionhandler object to session_set_save_handler() which does not contain the create_sid() and validateId() methods?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Backward Incompatible Changes

For PHP 8.6 additional deprecation notices will be emitted.

The actual removal of the affected functionality will happen no earlier than PHP 9.

Removed from this proposal

The following entries were originally added to this proposal and then dropped.

rfc/deprecations_php_8_6.txt · Last modified: by timwolla