What's new in PHP 8.4
PHP 8.4 will be released on November 21, 2024. It'll include property hooks, HTML 5 support, as well as chaining methods on new
without additional parentheses — a big one!
# Property hooks RFC
One of the biggest changes in modern-PHP history: the ability to define property hooks, eliminating the need for a lot of boilerplate code.
class BookViewModel { public function __construct( private array $authors, ) {} public string $credits { get { return implode(', ', array_map( fn (Author $author) => $author->name, $this->authors, )); } } public Author $mainAuthor { set (Author $mainAuthor) { $this->authors[] = $mainAuthor; $this->mainAuthor = $mainAuthor; } get => $this->mainAuthor; } }
The goal of property hooks is to remove a lot of getters and setters, by allowing each property to define its own get
and set
hooks. Hooks are optional, and you don't have to add both of them on a specific property. For example, a property with only a get
hook is virtual property.
There is a lot to say about property hooks, and I plan to write a followup post on them soon, so make sure to subscribe if you want to know when that one is done. One final thing I'd like to mention — probably what I'm most hyped about: property hooks can be defined in interfaces!
interface HasAuthors { public string $credits { get; } public Author $mainAuthor { get; set; } }
# new
without parentheses RFC
As if property hooks alone wasn't enough, PHP 8.4 has another feature that will save so much boilerplate code: you don't have to wrap new
invocations within parenthesis anymore to be able to chain methods on them. So instead of doing this:
$name = (new ReflectionClass($objectOrClass))->getShortName();
You can now do this:
$name = new ReflectionClass($objectOrClass)->getShortName();
I don't know about you, but I write a lot of code like this, and so I'm super happy that we're finally getting rid of those brackets. It doesn't only work for methods, by the way. You can also chain properties, static methods, constants — whatever you want. You can read all about this new feature in this dedicated post.
# Asymmetric visibility RFC
Another ground-breaking feature of PHP 8.4 is asymmetric visibility. Asymmetric visibility allows class properties to define their visibility (public
, protected
, or private
), based on the read or write context. The most common example of asymmetric visibility are public properties that can only be changed from within the class. Such a property would look like this:
class BookViewModel { public private(set) Author $author; }
Because "public properties that can only be changed within a private context" are the most common use-case for asymmetric visibility, there's also a shorthand available:
class BookViewModel { private(set) Author $author; // same as public private(set) }
Of course, you can also make properties only writeable within the protected scope:
class BookViewModel { public protected(set) Author $author; }
And naturally, the syntax works for promoted properties as well:
public function __construct( private(set) Author $author; ) {}
# array_find RFC
There's a pretty simple new function added in PHP 8.4, one of those functions that you have to wonder about "hang on, wasn't that available yet?" I guess most developers have grown used to third party collection classes, although I think having array_find()
natively in PHP is pretty nice.
The naming might be a bit confusing though, because what this function does is it takes an array and callback, and will return the first element for which the callback returns true
:
$firstMatch = array_find( $posts, function (Post $post) { return strlen($post->title) > 5; } );
There are also some variations of this function called array_find_key()
, array_any()
and array_all()
, you can read all about them here.
# Implicit nullable types deprecation
PHP had this weird behaviour where a typed variable with a default null
value would be made nullable automatically:
function save(Book $book = null) {} // Deprecated: Implicitly marking parameter $book as nullable is deprecated, // the explicit nullable type must be used instead
This behaviour is now deprecated and will be removed in PHP 9. The solution is to make Book
explicitly nullable:
function save(?Book $book = null) {}
# New HTML5 support RFC
PHP 8.4 adds a \Dom\HTMLDocument
class which is able to parse HTML5 code properly. The old \DOMDocument
class is still available for backwards compatibility.
$doc = \Dom\HTMLDocument::createFromString($contents);
You can read all about the new HTML 5 parser here.
# JIT changes RFC
PHP 8.4 changes the way the JIT is enabled. Previously, you had to set opcache.jit_buffer_size
to 0
in order to disable the JIT, but now you can disable it like so:
opcache.jit=disable opcache.jit_buffer_size=64m
The only way users can be affected by this change is if they did specify a opcache.jit_buffer_size
but no opcache.jit
. In that case, you'll have to add opcache.jit=tracing
to enable the JIT again.
Finally, there have also been some improvements to the JIT which makes it run faster in some cases, and use less memory.
# Lazy objects RFC
Finally, PHP 8.4 adds native support for lazy objects, a common pattern used by frameworks to build proxy objects with.
$initializer = static function (MyClass $proxy): MyClass { return new MyClass(123); }; $reflector = new ReflectionClass(MyClass::class); $object = $reflector->newLazyProxy($initializer);
# Exit and die as functions RFC
In PHP, exit
(and its alias die
) are kind of weird things: they can be used as a keyword like so: exit;
, but also like a function: exit(0);
. The function variant though isn't really a function, rather it is something that kind of behaves like a function, but not entirely:
- it didn't support named arguments;
- it couldn't be passed as a callable;
- it ignored
strict_types
; and - it did not follow usual type juggling semantics.
With PHP 8.4 though, exit()
and die()
are now properly treated as functions, and all of the above has been fixed. Note that the keyword variant without brackets of course still works the same.
# Object API for BCMath RFC
bcmath
used to only support a functional API. With PHP 8.4, you can now use an object-oriented API as well. What's especially cool about this feature is that these Number
objects support operator overloading, and thus you can use them directly in calculations!
use BCMath\Number; $num = new Number('1'); $num2 = new Number('2'); $result = $num + $num2; $result->value; // '3'
# The #[Deprecated]
attribute RFC
PHP now has a built-in attribute that can be used to mark methods, functions, and classes deprecated. Previously, you could already use a docblock like /** @deprecated */
, but PHP itself didn't do anything with it. While static analysers and IDEs were able to interpret these docblocks, you'd need external tooling to make sure all userland deprecations were detected.
Packages and frameworks can now instead rely on PHP's built-in #[Deprecated]
attribute, which also supports adding some metadata:
#[Deprecated("use newFunction() instead", since: "tempest/framework:1.1")] function oldFunction() { // … }
# Smaller additions
- The new
request_parse_body()
function that allows parsing RFC1867 (multipart) requests in non-POST HTTP requests. Read more - There are new static constructors to create
DateTime
andDateTimeImmutable
objects from a timestamp:DateTime::createFromTimestamp($timestamp)
andDateTimeImmutable::createFromTimestamp($timestamp)
- There are two new functions related to microseconds on
DateTime
andDateTimeImmutable
objects:DateTime::getMicrosecond()
andDateTimeImmutable::setMicrosecond($microsecond)
- There's now support for driver-specific PDO subclasses. Read more
- There's new support for driver-specific SQL parsers. Read more
# Backwards incompatible changes
- The
E_STRICT
constant is deprecated and its corresponding error level is removed. Read more - Some DOM element properties have been deprecated. Read more
- The GMP class is now final and cannot be extended anymore. Read more
- Additional value errors in MBString. Read more
- Additional value errors in PCNTL. Read more
- Ini settings for session.sid_length and session.sid_bits_per_character have been deprecated. You can simply comment them out in your php.ini file. Read more
- Read the full list here