What's new in PHP 8.1
While our Wikimedia servers are stuck with PHP 7.2 for a little longer, I'm very much looking forward to the day we can start using the new features every later PHP version came with. Continuing a series of similar posts here is my personal list of highly anticipated changes and features that are new in PHP 8.1, compared to PHP 8.0. As always in order of personal preference.
TL;DR: Enums. Intersection types with
readonly class properties.
never return type.
array_is_list(). First-class callables with
While putting this together I also stumbled upon PHP.Watch, a much more detailed resource for exactly what I do here. Written by a single person and going into way more detail than you ever asked for. 👍 Which leaves me with the task of compiling a short version that's focused on the MediaWiki development I mostly care about. Let's go.
- PHP finally got enumerations. I was waiting for this for a very long time. Before we had to give global constants a prefix (like PHP itself does) to not get lost, or put them in an "interface" that doesn't do anything but host a set of related constants. Still what PHP 8.1 gives us now is not that different. Enums in PHP are actually "built on classes and objects" and behave a lot like them. They can even have methods, but no state.
- Array unpacking now supports string-keyed arrays as well. The semantics follow strictly what
array_merge() does. These two lines do the same:
$result = array_merge(
[ 'a' => 0 ],
$result = [
'a' => 0,
array_is_list() is a fast, native way to check if an array is compatible with a
for loop. You can force any array to be such a list by running it through
- Pure intersection types require a value to satisfy multiple type constraints the same time. A good example is
Iterator&Countable. Note that union types with the syntax
Iterator|Countable exist since PHP 8.0.
never (previously known as "noreturn") is a strict return type for functions that, for example, are guaranteed to throw an exception and never give the control flow back to the caller. It's meant to replace
@return noreturn comments you might have used before.
- Class properties can be marked as
readonly. These can be initialized once from anywhere within the class (doesn't need to be the constructor) and never changed again.
new keyword can be used in initializers, most notably in method signatures. A good example is
public function __construct( Logger $logger = new NullLogger() ). Combining this with constructor property promotion is possible.
- We got a new syntax called "first-class callables" that allows us to replace arrays like
$callback = [ $this, 'methodName' ]; with
$callback = $this->methodName(...); and then call it with
$callback();. Note that the three dots are the actual syntax for this, similar to the variable-length arguments syntax
methodName( ...$args ) we have since PHP 5.6.
final modifier can be used on class constants. Such a constant can't be changed in subclasses.
htmlspecialchars() and such will not return an empty string any more when the input is not valid UTF-8. They now use the
ENT_SUBSTITUTE mode by default. This mode replaces bad characters will the Unicode replacement character U+FFFD.
- A static variable in a method will now behave like a static property and be visible to subclasses that override the method.
- You should check your code for usages of
is_resource() and replace it with checks for
false whenever possible. The reason is that more features don't return resource identifiers any more, but objects.
Some more things that are most probably mistakes in your code will spit out deprecation warnings now. For example,
$array[ 1.5 ] won't silently drop the
.5 any more. Internal functions will not silently accept
null any more when a parameter is not really nullable. While one might want to classify these as (future) breaking changes, personally I think of these more as issues with my code I want to fix.
PHP 8.1 was released in November 2021 and will be actively supported for 2 years.