PHP 8.4

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?

  1. Data Validation
    Property hooks allow validation of data before it's set, ensuring that only valid values are assigned to properties.

  2. Computed Properties
    You can dynamically compute property values when they're accessed, such as concatenating multiple fields into a single string.

  3. Encapsulation
    Hooks enable encapsulating logic for property access and modification without requiring separate getter and setter methods.

  4. 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:

  1. 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.

  1. 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

  1. 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
    

    Documentation

  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
    

    Documentation

  3. 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)
    

    Documentation

  4. 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)
    

    Documentation

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
5 min. read