PHP 8.1: Warning on compact function calls with non-string and non-array string parameters

Version8.1
TypeChange

compact function creates an array containing variable names and their values, from a list of variable names passed to the function.

$fruit = 'Apple';
$color = 'Red';
$origin = 'New Zealand';

compact('fruit', 'color', 'origin');
// ['fruit' => "Apple", 'color' => "Red", 'origin' => "New Zealand"]

Historically, the compact function has been forgiving; On string values that cannot be resolved to a variable syntax, this function skips that value without further warnings.

In PHP 7.3, the compact function was changed to emit a notice on undefined variables, and later updated to emit a warning instead in PHP 8.0.

compact function's documentation shows that it will only accept string parameters, or only array values with string values.

function compact(array|string $var_name, array|string ...$var_names): array {}

Despite the function documentation, the compact function accepted non-string and non-array parameters, but silently ignored them.

For example, the following snippets does not emit any warnings prior to PHP 8.1.

compact(null);
// []
compact(new stdClass());
// []
compact(42);
// []
$a = 1; $b = 2;
compact('a', 42, 'b');
// ['a' => 1, 'b' => 2]

Declaring strict-types with declare(strict_types=1) does not make compact function perform a strict type checking.


This behavior is changed in PHP 8.1; In PHP 8.1, compact function emits a warning on non-string or an array that does not contain all-string keys.

compact(null);
// []
PHP Warning:  compact(): Argument #1 must be string or array of strings, null given in ... on line ...

Note that declaring strict-types (declare(strict_types=1)) still has no impact, and does not cause compact function to throw type errors.

The warning is emitted for numbers (that cannot be used to start a variable name), objects, null, bool values, or on arrays if it contains a value that is not of an allowed type.

$a = 16;
compact('a', [null, false, 'a', 42], new stdClass);
PHP Warning:  compact(): Argument #2 must be string or array of strings, null given in ... on line ...
PHP Warning:  compact(): Argument #2 must be string or array of strings, bool given in ... code on line ...
PHP Warning:  compact(): Argument #2 must be string or array of strings, int given in ... on line ...
PHP Warning:  compact(): Argument #3 must be string or array of strings, stdClass given in ... on line ...

The warning is emitted for each occurrence of illegal types.

Related Changes


Backwards Compatibility Impact

compact function allowed non-string and non-string-array values prior to PHP 8.1, despite the documentation. The new warning emitted on PHP 8.1 can be avoided by simply not passing those values to the compact function, either by removing the known illegal values, or by filtering the values prior to passing them to the compact function.

The @ error suppressor operator can suppress the warning (@compact(null)), but it is often not a good idea because it does not prevent the root cause.

In PHP 9.0, this warning will be upgraded to throw a TypeError exception.


Discussion Implementation