Introduction
Despite claims that PHP is outdated, the language continues to evolve, bringing exciting new features and improvements with each release. These enhancements not only boost code quality but also make programming more enjoyable for developers. In this article, we’ll explore the key features and improvements introduced in PHP 8.4. Let’s dive in!
Release Date: PHP 8.4 is scheduled for release on November 21, 2024.
Property Hooks
Property Hooks are a powerful new feature in PHP 8.4, allowing developers to define custom behavior for getting and setting properties directly in class definitions. This feature makes it easier to validate or manipulate data when accessing or modifying class properties, leading to cleaner, more maintainable code.
Why Are Property Hooks Useful?
-
Data Validation
Property hooks allow validation of data before it's set, ensuring that only valid values are assigned to properties. -
Computed Properties
You can dynamically compute property values when they're accessed, such as concatenating multiple fields into a single string. -
Encapsulation
Hooks enable encapsulating logic for property access and modification without requiring separate getter and setter methods. -
Simplified Syntax
You can now define hooks directly within constructor parameters, making class definitions more concise.
Example Usage
Here’s an example of how Property Hooks work in PHP 8.4:
class Address
{
public function __construct(
private string $city {
get {
// Manipulate or filter the city name on access
return ucfirst($this->city);
}
set {
// Validate or sanitize input before assigning
if (empty($value)) {
throw new InvalidArgumentException("City cannot be empty.");
}
$this->city = trim($value);
}
},
private string $country
) {}
public string $fullAddress {
get => "{$this->city}, {$this->country}"; // Dynamically compute the full address
set {
// Split a string into city and country
[$this->city, $this->country] = explode(', ', $value);
}
}
}
Asymmetric Visibility
Asymmetric Visibility is a new feature in PHP 8.4 that allows developers to define different visibility levels for the getter and setter of a property. This feature provides greater control over how properties are accessed and modified, enabling scenarios where a property is readable publicly but writable only within the class or privately.
How It Works
In PHP 8.4, you can declare asymmetric visibility for properties either within the constructor or directly in the class. For example:
-
Constructor Declaration:
You can specify asymmetric visibility while declaring properties in the constructor:
public function __construct(public private(set) string $name) {}
In this example, the $name property is readable publicly but can only be modified privately.
-
Direct Class Declaration:
Asymmetric visibility can also be defined directly in the class:
public private(set) string $name;
This achieves the same functionality as the constructor declaration: the property can be read publicly but updated only within the class.
3. Simplified Syntax:
If you don't need the property to be publicly readable, you can omit public
altogether:
private(set) string $name;
This keeps the code concise and improves clarity.
Practical Example
Here’s an example showcasing Asymmetric Visibility:
class User
{
public private(set) string $username;
public function __construct(string $username)
{
// Setting the property during initialization
$this->username = $username;
}
public function changeUsername(string $newUsername): void
{
// Updating the property internally
$this->username = $newUsername;
}
}
$user = new User('john_doe');
// This will work, as the getter is public
echo $user->username; // Output: john_doe
// This will trigger an error, as the setter is private
$user->username = 'jane_doe'; // Error: Cannot access private property
In this example:
The username
property is publicly readable (public
getter) but privately writable (private
setter). Modifications to the username
can only happen through class methods like changeUsername
.
New Search Functions for Arrays
PHP 8.4 introduces four powerful and highly useful functions for working with arrays. These new functions make it easier to search for elements and validate conditions across arrays, streamlining common tasks for developers.
The New Functions
-
array_find
Finds the first element in an array that satisfies a given condition.$numbers = [1, 2, 3, 4, 5]; $evenNumber = array_find($numbers, fn($n) => $n % 2 === 0); echo $evenNumber; // Output: 2
-
array_find_key
Finds the key of the first element that satisfies a given condition.$fruits = ['a' => 'apple', 'b' => 'banana', 'c' => 'cherry']; $key = array_find_key($fruits, fn($fruit) => $fruit === 'banana'); echo $key; // Output: b
-
array_any
Checks if any element in the array satisfies a given condition.$numbers = [1, 3, 5]; $hasEven = array_any($numbers, fn($n) => $n % 2 === 0); var_dump($hasEven); // Output: bool(false)
-
array_all
Checks if all elements in the array satisfy a given condition.$numbers = [2, 4, 6]; $areAllEven = array_all($numbers, fn($n) => $n % 2 === 0); var_dump($areAllEven); // Output: bool(true)
Method Calls Without Parentheses
Before PHP 8.4, chaining method calls immediately after object instantiation required wrapping the instantiation in parentheses, like this:
(new Foo($bar))->baz();
With PHP 8.4, this syntax becomes much cleaner. You can now omit the parentheses around the instantiation and write:
new Foo($bar)->baz();
The updated syntax eliminates unnecessary parentheses, making code more concise and easier to follow. It also improves readability by aligning PHP's syntax closer to how developers naturally think about chaining methods.
Here’s an example to illustrate the difference:
// Before PHP 8.4
$result = (new Calculator())->add(10)->subtract(5)->getResult();
// PHP 8.4 and Beyond
$result = new Calculator()->add(10)->subtract(5)->getResult();
New mb_ucfirst
and mb_lcfirst
Functions
PHP has long provided the ucfirst
and lcfirst
functions to convert the first character of a string to uppercase or lowercase. While these functions work well with single-byte encodings, they struggle with multi-byte characters, making them unsuitable for handling non-Latin scripts.
The mbstring
extension already offers multi-byte safe alternatives for many PHP string functions, but until PHP 8.4, it lacked counterparts for ucfirst
and lcfirst
. With PHP 8.4, this gap is filled with the introduction of mb_ucfirst
and mb_lcfirst
. These functions ensure accurate casing transformations for multi-byte strings, expanding PHP's capability to handle multilingual applications effectively.
#[\Deprecated] Attribute
PHP 8.4 introduces the #[\Deprecated]
attribute, allowing developers to explicitly mark functions, class constants, and enum cases as deprecated. While PHP has historically supported deprecation warnings for internal functions and constants, this attribute empowers developers to signal deprecation for their own code.
When applied, the #[\Deprecated]
attribute triggers warnings during runtime or static analysis, encouraging developers to transition away from outdated code. This feature enhances code maintainability and provides a structured way to manage deprecations in evolving projects.
Example:
#[\Deprecated(reason: "Use newFunction() instead.")]
function oldFunction() {
// Deprecated functionality
}
This addition is a significant step forward in helping teams manage legacy codebases while planning for future improvements.
Conclusion
PHP 8.4 introduces valuable features that enhance both development efficiency and code quality. Property hooks, cleaner syntax for method calls, and new multi-byte safe string functions like mb_ucfirst
and mb_lcfirst
improve flexibility and readability. The addition of new array functions and the #[\Deprecated]
attribute also help developers manage data and maintain cleaner codebases. Overall, PHP 8.4 continues to evolve, making it a powerful tool for modern web development.
“Writing is seeing the future.” Paul Valéry