With holidays so heavily stacked at the end of the year, one would think software development would wind down for the season. Instead, we have already seen one major release in November. WordPress 6.7 stormed in with impressive design additions and improvements to several key functionalities. It is fitting that the scripting language WordPress is based on would also release its newest version in the same month. As it happens every year, PHP 8.4 was released at the end of November, bringing some truly amazing changes.
PHP 8.4 not only brings exciting new features but also–and more importantly– aims to simplify how the language is used. Additionally, the release seeks to streamline the development process by eliminating some well-known challenges. In this blog post, we will tell you everything you need to know about PHP 8.4, so read on.
Functions for Finding Array Items
Let us begin with something that one would have assumed was already possible in PHP: searching array elements for members that match specific criteria defined in a callback function. Instead, that functionality is making its debut with PHP 8.4. It comes in the form of the new array_find() function alongside three related ones. They are like array_find(), but each has a specific context.
- array_find_key() – This function’s return value is the matching element’s key instead of the value of the element itself;
- array_all() – This function will return true when every element in the queried array matches the test;
- array_any() – Finally, this function returns true when there is at least one match in the element array being tested.
That said, here is a practical example of each function and what it returns as a response when tested.
$fruits = [
'apple' => 'Red Delicious',
'banana' => 'Cavendish',
'cherry' => 'Bing',
'date' => 'Medjool'
];
// Find the first fruit name that has a space in it
var_dump(array_find($fruits, function (string $name) {
return strpos($name, ' ') !== false;
})); // Returns "Red Delicious"
// Find the array key for the first fruit name longer than 7 characters
var_dump(array_find_key($fruits, function (string $name) {
return strlen($name) > 7;
})); // Returns "date"
// Check if any fruit name has exactly 4 characters
var_dump(array_any($fruits, function (string $name) {
return strlen($name) === 4;
})); // Returns false
// Verify if all fruit names start with an uppercase letter
var_dump(array_all($fruits, function (string $name) {
return ctype_upper($name[0]);
})); // Returns true
As you can see, these new functions will greatly simplify one of the most common operations when it comes to arrays.
HTML5 Parsing
HTML5 has been around for a while. It was initially released in 2008 but cemented its place as the standard for modern web pages in 2014. That is a long time for PHP’s Document Object Model parsing to be stuck on HTML 4.01.
Fortunately, PHP 8.4 solves this discrepancy by introducing a new class: DomHTMLDocument. That removes the need to upgrade the existing DomDocument class, preserving its functionality with older HTML standards.
The new class supports these constructors.
- createFromString($html)
- createFromFile($path)
- createEmpty()
Since PHP 8.4 supports HTML5 fully, you can import the contents of an HTML5 page like this.
$xmlFeed = DomHTMLDocument::createFromString($rssFeedXml)
Finally, the parser from above supports the usual semantic HTML5 tags, such as main, article, and section.
Property Hooks
Next, let us talk about one of the significant changes coming with PHP 8.4: property hooks.
Prior to version 8.4, properties in a private class (preventing direct access to them) had to use getters and setters to retrieve property values or change them, respectively. However, that approach requires a lot of repetitive code, which can swell up even more as the number of properties increases. Like this, for example.
class Book {
private string $title;
private string $author;
public function __construct(string $title, string $author) {
$this->title = $title;
$this->author = $author;
}
// Getter for title
public function getTitle(): string {
return $this->title;
}
// Setter for title
public function setTitle(string $title): void {
if (strlen($title) > 100) {
throw new InvalidArgumentException('Title is too long');
}
$this->title = $title;
}
// Getter for author
public function getAuthor(): string {
return $this->author;
}
// Setter for author
public function setAuthor(string $author): void {
if (empty($author)) {
throw new InvalidArgumentException('Author name cannot be empty');
}
$this->author = $author;
}
}
// Usage
$book = new Book('1984', 'George Orwell');
echo $book->getTitle(); // Outputs: 1984
$book->setTitle('Animal Farm');
echo $book->getTitle(); // Outputs: Animal Farm
An alternative was to use PHP’s __get and __set magic methods to simplify property management. However, that approach can be harder to follow, and the logic can get messy, leading to unintended behavior. Here is an example of what that would look like.
class Book {
private string $title;
private string $author;
public function __set(string $key, $value): void {
if ($key === 'title') {
if (strlen($value) > 100) {
throw new InvalidArgumentException('Title is too long');
}
$this->title = $value;
} elseif ($key === 'author') {
if (empty($value)) {
throw new InvalidArgumentException('Author name cannot be empty');
}
$this->author = $value;
}
}
public function __get(string $key) {
if ($key === 'title') {
return $this->title;
} elseif ($key === 'author') {
return $this->author;
}
}
}
// Usage
$book = new Book();
$book->title = '1984'; // Sets title
echo $book->title; // Outputs: 1984
$book->author = 'George Orwell'; // Sets author
echo $book->author; // Outputs: George Orwell
However, with the introduction of Property Hooks, developers can handle validation and functionality directly from within the property definitions. As you can imagine, that will keep the code clean and better organized. Here is another example using the Property Hooks.
class Book {
public string $title {
set(string $value) {
if (strlen($value) > 100) {
throw new InvalidArgumentException('Title is too long');
}
$this->title = $value;
}
get {
return $this->title;
}
}
public string $author {
set(string $value) {
if (empty($value)) {
throw new InvalidArgumentException('Author name cannot be empty');
}
$this->author = $value;
}
get {
return $this->author;
}
}
}
// Usage
$book = new Book();
$book->title = '1984'; // Validates and sets title
$book->author = 'George Orwell'; // Validates and sets author
echo $book->title; // Outputs: 1984
echo $book->author; // Outputs: George Orwell
Even at a glance, it is obvious that this code is much more readable and tidy than the previous two examples. Because the property and its intended behavior are defined together, they are much easier to understand, therefore reducing the chance for unintended consequences. This approach is a big step towards simplifying and modernizing the object-oriented code for PHP developers.
Asymmetric Visibility
Speaking of getters and setters, the PHP 8.4 update brings another cool change to them. Previously, they were the default way to access private or protected properties within their classes. There was no way to set the visibility of properties depending on how they were accessed.
PHP 8.4 changes that for the better. The Asymmetric Visibility feature allows properties to have different levels of visibility. For example, a property can be both public when read and private when set. Here is an example.
class Book
{
public private(set) string $title = 'The Great Gatsby';
}
$book = new Book();
print $book->title; // Prints "The Great Gatsby"
$book->title = '1984'; // Error (visibility)
As you can see, the Book class is public except when it is being set. Then, it is private. This feature has an even more abbreviated version, in case you want to use it as well.
class Book
{
// public is assumed when the context is not setting
private(set) string $title = 'To Kill a Mockingbird';
}
$book = new Book();
print $book->title; // Prints "To Kill a Mockingbird"
$book->title = '1984'; // Error (visibility)
You can already tell from the comment in the code, but Asymmetric Visibility assumes visibility is public when not setting.
Other Additions
The four improvements we discussed so far are not the only ones PHP 8.4 brings, though! There are a slew of other smaller improvements, so we have compiled a quick list to highlight the most important and exciting ones.
- Calling new – When calling new and chaining its methods, you no longer need to place its invocations in parentheses. Here is an example of how it looks now:
- $Books = new Books()->getAuthor()->getTitle();
- Multibyte Support for Trim Functions – PHP 8.4 introduces three new functions that can remove white space or special characters from strings that may contain multibyte characters. They trim both ends or the left or right end as necessary:
- mb_trim()
- mb_ltrim()
- mb_rtrim()
- exit() and die() – In previous versions of PHP, exit and die could behave like functions–even though they were keywords. PHP 8.4 promotes them to fully-fledged functions, alleviating a lot of the headaches that came with their odd behavior before;
- Lazy Objects – The long-awaited native support for Lazy Object finally arrives with PHP 8.4. It is now possible to create objects that will not be fetched until they are required;
- JIT Changes – The new release delivers some JIT improvements that will make it run better and more efficiently in some cases. Additionally, you can deactivate the JIT like this now instead of setting the value of opcache.jit_buffer_size to zero:
- opcache.jit=disable
That concludes the additions and changes introduced with the PHP 8.4 update. Let us move on to some deprecations.
Deprecations
As is always the case when a new version of software is released, some deprecations must be mentioned.
- GET/POST Sessions – Using the session.use_only_cookies and session.use_trans_sid settings with PHP 8.4 will trigger a deprecation warning. With PHP 9, the settings will no longer be available because PHP is trying to move away from storing session ID data in GET/POST parameters;
- Method and Function Deprecations:
- DOMImplementation::getFeature($feature, $version) (removed, not just deprecated);
- Deprecate SplFixedArray::__wakeup();
- Deprecate xml_set_object() and xml_set_*_handler() for string method names;
- Deprecate dba_key_split() when passing null or false;
- Deprecate mysqli_ping(), mysqli::ping(), mysqli_refresh(), mysqli_kill();
- Deprecate the second parameter to mysqli_store_result();
- Deprecate lcg_value();
- Deprecate uniqid();
- Deprecate md5(), sha1(), md5_file(), and sha1_file();
- Deprecate strtok();
- Constants:
- Deprecate DOM_PHP_ERR;
- Deprecate SUNFUNCS_RET_STRING, SUNFUNCS_RET_DOUBLE, SUNFUNCS_RET_TIMESTAMP;
- Deprecate E_STRICT;
- Deprecate SOAP_FUNCTIONS_ALL;
- Properties:
- Soft-deprecated DOMDocument and DOMEntity;
- Deprecate session.sid_length and session.sid_bits_per_character;
- Others:
- Deprecate the “S” tag in unserialize();
- Deprecate proprietary CSV escaping mechanism;
- Deprecate returning non-string values from a user output handler;
- Deprecate passing incorrect data types for options to ext/hash functions;
- Deprecate a single underscore as a class name.
With these deprecations, our overview of what is coming with the PHP 8.4 release is completed. If you are using any of the deprecated items we listed above, please ensure you take that into account when updating to the new version.
The Next Chapter in PHP
This latest iteration of PHP introduces some truly exciting changes to its functionality. The fact that it finally supports HTML5 parsing is a huge leap forward, let alone all the other cool things it brings.
We are very excited about everything PHP 8.4 has in store. Not only that, the newest version of the scripting language is available and fully supported on all our servers. Check out our tutorial on how to change your PHP version to the newest one. Remember to ensure your application is compatible with PHP 8.4, though!