What’s new in PHP 8.2

The PHP 8.2 release is just around the corner, and with it comes a number of fixes, improvements and deprecations.

It is scheduled to be released late in November 2022. A third beta version of PHP 8.2.0 has now been released for testing. Before going into PHP 8.2 let’s take a quick look at the features of PHP 8.0 and 8.1.

Some of the enhanced features in PHP 8.0 & PHP 8.1 are:

  • Named parameters
  • Match syntax
  • Union types
  • Constructor Property Promotion
  • JIT (which affects how PHP executes source code)
  • Intersection types
  • Read-only properties
  • Enums
  • Fibers
  • Never return type

In this blog post, we'll take a look at some of the most anticipated features coming in PHP 8.2. We'll also discuss how these new features can benefit your website or application. So without further ado, let's dive in!

Table of contents

  1. PHP 8.2 Breaking Changes
  2. Deprecations in PHP 8.2

PHP 8.2 Breaking Changes

Here is a complete list of the new features and improvements in PHP 8.2.

  1. New read-only class property
  2. Constants in Traits
  3. Fetch enum Properties in const Expressions
  4. Disjunctive Normal Form (DNF) Types
  5. Redact Sensitive Parameters in Back Traces
  6. New mysqli_execute_query Function and mysqli::execute_query Method
  7. New ini_parse_quantity function
  8. New memory_reset_peak_usage function
  9. Allow Dynamic Properties attribute
  10. Curl: curl_upkeep function
  11. Curl: CURLINFO_EFFECTIVE_METHOD support in curl_getinfo function

#1 New read-only class property

Previously, PHP 8.1 introduced read-only properties. With PHP 8.2, it is now possible to declare an entire class as read-only.

When you declare an entire class read-only, all the properties in it will inherit read-only properties automatically.

For example, if we have to write a PHP code with readonly property.

To declare the entire class as readonly, ‌you have to add it in ‌every variable inside the class:

class MyClass
{
    public readonly string $bookName,
    public readonly int $count,
    public readonly string $authorName,
    public readonly int $price
}

With PHP 8.2, you can simply add it before the class name.

class readonly MyClass
{
    public string $bookName,
    public int $count,
    public string $authorName,
    public int $price
}

As well as abstract and final classes, you can declare them as read-only. There is no significance to the order in which the keywords appear.

abstract readonly class ClassName {}
final readonly class ClassName {}

Also you cannot declare readonly for certain PHP features:

  • Enum
  • Traits
  • Interfaces

#2 Constants in Traits

Traits are similar to classes, the major difference between a trait and a class is that traits are used only for grouping methods in a fine and consistent manner.

You can only declare methods and properties inside a trait. Now, with the new PHP 8.2 improvement, you can define constants.

Example:

trait Foo
{
    public const CONSTANT = 1;
 
    public function bar(): int 
    {
        return self::CONSTANT;
    }
}

You cannot access the constant through trait's name but now with the new update you can easily do it.

trait Foo 
{
    public const CONSTANT = 1;
 
    public function bar(): int 
    {
        return Foo::CONSTANT;
    }
}

Foo::CONSTANT;

If the constant is declared as public, you can also access it through the class which uses the trait.

class MyClass
{
    use Foo;
}

MyClass::CONSTANT; // 1

#3 Fetch enum Properties in const Expressions

This RFC proposes to allow the use of ->/?-> to fetch properties of enums in constant expressions in PHP 8.2.

The primary reason for this change is to enable enum value and name properties to be retrieved in array keys, which are not allowed for enum objects. In the current implementation, the enum case value cannot be expressed without repeating.

This means that the following code now works:

enum A: string 
{
    case B = 'B';    
    const C = [self::B->value => self::B];
}

#4 Disjunctive Normal Form (DNF) Types

The Disjunctive Normal Form (DNF) is a way to organize boolean expressions that involves disjunctions between conjunctions - in boolean terms, that's ORs between ANDs.

We can use a type declaration written in DNF for combining Union and Intersection types that can be parsed by the parser. Using PHP 8.2's new DNF types feature correctly can make it powerful.

A DNF type could include property declarations, parameter declarations, and return values as follows:

// Accepts both A and B objects,
// OR objects that implement D.

(A&B)|D

// Accepts objects implementing C, 
// Or a child of X that implements D,
// OR null.

C|(X&D)|null

// Accepts objects that implement all three of A, B, and D, 
// OR an int, 
// OR null.

(A&B&D)|int|null

Example of DNF type:

function generateSlug((HasBookTitle&HasBookId)|null $bookInfo)
    if ($bookinfo === null) {
        return '';
    }

    return 
        strtolower($bookInfo->getBookTitle()) 
        . $bookinfo->getBookId();
}

In the above example, (HasBookTitle&HasBookId)|null is the DNF type.

This is a great feature, especially since we can now have nullable intersection types, which is arguably the most important use case.

#5 Redact Sensitive Parameters in Back Traces

Any point in the code's execution can be traced in PHP, as with almost any other programming language. By using stack tracing, you can easily diagnose errors and find performance bottlenecks in your code.

Production errors are typically sent to a monitoring service that tracks, notifies developers when something goes wrong, and keeps track of them consistently. Stack traces are one of the greatest feature for many performance monitoring tools.

It is necessary to send stack traces to third-party monitoring services for monitoring, but those stack traces can include sensitive information such as environment variables, passwords, and usernames.

PHP 8.2 added a support to mark the sensitive parameters with an attribute \SensitiveParameter.

function netBankingInfo(
    $userName,
    #[\SensitiveParameter] $password,
) {
    throw new Exception('Error');
}
 
netBankingInfo('userName', 'password');


/*
Fatal error: Uncaught Exception: Error in test.php:8
Stack trace:
#0 test.php(11): test('Andrew', Object(SensitiveParameterValue), 'password')
#1 {main}
thrown in test.php on line 8
*/

The value with the \SensitiveParameter attribute will be replaced with the \SensitiveParameter object and the real value will not be stored in the trace. It encapsulates the parameter and can be used if you need it for any specific reason.

#6 New mysqli_execute_query Function and mysqli::execute_query Method

The MySQLi extension provides a new mysqli_execute_query function and execute_query method to prepare, bind, execute, and retrieve results from an SQL.

The function and method will accept the SQL query and it will be prepared, bound and executed which in turn returns the mysqli_result object on successful or false on unsuccessful.

In simple words, it is a short-cut to mysqli::prepare(), mysqli_stmt::bind_param(), mysqli_stmt::execute, and mysqli_stmt::get_result() calls.

$query = 'SELECT uid, username FROM users WHERE uid = ?';

$statement = $connection->prepare($query);

$statement->bind_param('4587', $uid);

$statement->execute();

$result = $statement->get_result();

With PHP 8.1, there is no need with binding the reference:

$query = 'SELECT uid, username FROM users WHERE uid = ?';

$statement = $connection->prepare($query);

$statement->bind_param('4587', $uid);

$statement->execute('4587', $uid);

$result = $statement->get_result();

By introducing mysqli_execute_query in PHP 8.2, it would be possible to simplify the above code in a single line:

$query = 'SELECT uid, username FROM users WHERE uid = ?';

$result = $mysqli->execute_query($sql, [$uid]);

#7 New ini_parse_quantity function

PHP's ini_parse_quantity function parse any size of data and return it as several bytes in a particular format. Using this function, you can parse an INI value provided or existing in a PHP application.

function ini_parse_quantity(string $shorthand): int {
}

By examining the last character suffix in the given $shorthand, the ini_parse_quantity function attempts to parse it and if it matches one of the following recognized suffixes, the returned value is multiplied by the unit specified to calculate the return value.

#8 New memory_reset_peak_usage function

The memory_reset_peak_usage_function helps you to reset the peak memory usage returned by the memory_get_peak_usage function.

The memory_get_peak_usage function just returns the absolute peak memory usage throughout the run but with the addition of the new memory_reset_peak_usage_function in PHP 8.2 you can easily reset the memory usage.

An application that invokes or iterates an action multiple times might find this helpful in tracking peak memory usage.

function memory_reset_peak_usage(): void {
}

Usage:

$str = str_repeat('apm', 1024 * 1024 * 4);
memory_get_peak_usage(); // 12933552

unset($str);

$str = str_repeat('a', 1024 * 1024 * 3);
memory_get_peak_usage(); // 12933592

In the code above, the character a is repeated 12933008 times in the variable $string. PHP's memory usage reached 12933552 bytes at its peak. Even when the $str variable is destroyed, and a smaller string is written in its place, 12933592 bytes remains the peak memory usage.

 $str = str_repeat('a', 1024 * 1024 * 4);
 memory_get_peak_usage(); // 4590752

 unset($str);
 memory_reset_peak_usage();

 $str = str_repeat('a', 1024 * 1024 * 3);
 memory_get_peak_usage(); // 3542648

The memory_reset_peak_usage function will reset the peak memory usage that the PHP engine has recorded, once the $str variable is destructed.

#9 Allow Dynamic Properties attribute

PHP 8.2 added a new attribute called #AllowDynamicProperties which helps you to avoid the deprecation notice for dynamic properties.

 #[AllowDynamicProperties]
 class User() {}

 $user = new User();
 $user->userName = 'Andrew';

It is declared in the global namespace which doesn't accept any parameters.

#10 curl_upkeep function

curl_upkeep is a new function added to the Curl extension. Upkeep work is performed by curl_upkeep() to keep a Curl connection active. Curl does not support connection upkeep for all types of connections.

Connection upkeep is currently available only for HTTP/2 connections. A small amount of traffic is usually sent to keep a connection alive. HTTP/2 maintains its connection by sending a HTTP/2 PING frame.

function curl_upkeep(CurlHandle $handle): bool {
}

The Curl function accepts and returns the CurHandle object after PHP 8.0. The function ignores calls that aren't established or already closed or if the upkeep mechanisms aren't available.

#11 Curl: CURLINFO_EFFECTIVE_METHOD support in curl_getinfo function

The curl_getinfo function returns the information about a particular Curl transfer. In PHP 8.2, they have added a support to return the effective method of a request.

By default, without specifying any parameter in the curl_getinfo it returns an array of all information related to the Curl transfer. Now the array will have an extra element with the key effective_method, which contains the name of the effective method of the HTTP request.

Usage:

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://myshop.com');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);

$info = curl_getinfo($ch);
var_dump($info);

You can also pass the CURLINFO_EFFECTIVE_METHOD constant to the curl_getinfo function call to specifically return the effective_method.

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://myshop.com');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);


$info = curl_getinfo($ch, CURLINFO_EFFECTIVE_METHOD);
var_dump($info);

Deprecations in PHP 8.2

Take a look at what's being deprecated in PHP 8.2, and how it might affect your code.

  1. ${var} string interpolation deprecated
  2. Dynamic Properties are deprecated
  3. Classes with #[AllowDynamicProperties] attribute
  4. Partially-supported callable are deprecated
  5. utf8_encode and utf8_decode functions deprecated
  6. Mbstring: Base64, Uuencode, QPrint, and HTML Entity encodings are deprecated

#1 ${var} string interpolation deprecated

In PHP, double quotes and heredoc syntax can be used to replace variables in string literals.

$pm = 'Performance Monitoring';

echo "Application $pm"; // Application Performance Monitoring
echo "Error & $pm"; // Error & Performance Monitoring

It is also a good idea to add a {} around the variable for better readability. In addition to curly braces, PHP also supports the dollar sign outside of them.

$pm = 'Performance Monitoring';

echo "Application ${pm}"

String interpolation methods such as those described above are deprecated in PHP 8.2.

The below method is compatible in all PHP versions apart form the deprecation notice.

echo "Application {$pm}";

#2 Dynamic Properties are deprecated

Without declaring the properties in the class you can dynamically get and set properties in all PHP classes.

class getCustInfo {
    public string $id;
    public string $custName;
    protected int $age;
}

$custInfo = new getCustInfo();

$getCustInfo->contactNo = '9854725647';

We haven't declared the property contactNo inside the getCustInfo class. Since PHP supports dynamic properties, it allows setting it.

To prevent the above error you can use the __get() and __set() magic methods.

However, dynamic properties can lead to potential bugs and unexpected behaviors in applications, since they do not require a strict class declaration. PHP silently allows all dynamic properties, so a typo could go unnoticed in a statement setting a property.

When a value is set to an undeclared class property in PHP 8.2 or later, a deprecation notice is emitted.

Deprecated: Creation of dynamic property User::$name is deprecated in ... on line ...

The deprecation notice also prohibits you from setting the properties within the class.

class getCustInfo {
    public string $id;
    public int $contactNo;
    protected int $age;

    public function __construct() {
            $this->custName = 'Andrew';
        }
}

$custInfo = new getCustInfo();

To avoid the above deprecation notice, there are three exceptions:

  1. Classes with #[AllowDynamicProperties] attribute
  2. stdClass and its sub-classes
  3. Classes with __get and __set magic methods

#3 Classes with #[AllowDynamicProperties] attribute

With the #[AllowDynamicProperties] you can easily avoid the deprecation notice warning message. This attribute stops PHP from emitting the deprecation notice on dynamic properties.

#[AllowDynamicProperties]
class getCustInfo {
    public string $id;
    public int $contactNo;
    protected int $age;

    public function __construct() {
            $this->custName = 'Andrew';
        }
}

$custInfo = new getCustInfo();

This behavior will be inherited by all child classes of that class.

i.) stdClass and its sub-classes

stdClass will allow you to set the dynamic property since by default internally it contains the [AllowDynamicProperties] attribute.

$object = new stdClass();
$object->foo = 'bar';
class User extends stdClass {}

$object = new User();
$object->foo = 'bar';

stdClass and any of its subclasses also inherits the behaviour and does not emit dynamic property deprecation notice.

ii.) Classes with __get() and __set() magic methods

The class that is declared with the __set() method will be excluded from the dynamic deprecation notice.

class getCustId {
    public function __set(string $custId, mixed $value): void {

    }
}

$getCustId = new getCustId();
$user->custId = '7584';

The snippet above does not emit a deprecation notice because the User class implements the __set magic method.

Note that setting a dynamic property from within the __set method is still deprecated:

class getCustId {
    public function __set(string $custId, mixed $value): void {
		$this->{$custId} = $value;
    }
}

$getCustId = new getCustId();
$user->custId = '7584';

The above code will emit the deprecation notice.

#4 Partially-supported callable are deprecated

PHP 8.2 deprecates certain patterns of callables that do not work with the $callable() pattern.

Callables can be created in several ways in PHP. In addition, callables can be called with or without parameters using the $callable() syntax.

Using $callable() does not allow you to directly interact with these callables. They can only be accessed by calling call_user_func($callable).

Unaffected callable patterns

There will be no warning regarding deprecation for the below callable patterns.

$callable = 'strlen';
$callable = ['MyClass', 'myMethod'];
$callable = 'MyClass::myMethod'];
$callable = Closure::fromCallable();
$callable = [$this, 'myMethod'];
$callable = [new MyClass(), 'myMethod'];
$callable = strlen(...);

Deprecated callable patterns

$callable = "self::method";
$callable = "parent::method";
$callable = "static::method";
$callable = ["self", "method"];
$callable = ["parent", "method"];
$callable = ["static", "method"];
$callable = ["MyClass", "MyParentClass::myMethod"];
$callable = [new MyClass(), "MyOtherClass::myMethod"];

#5 utf8_encode and utf8_decode functions deprecated

The built-in PHP functions utf8_encode and utf8_decode helps you in converting the strings between ISO-8859-1 and UTF-8 encodings.

Even if the source text is not encoded in ISO-8859-1, the above functions would convert the string into ISO-8859-1 and UTF-8 encodings.

utf8_encode('apm');
uft8_decode('apm');

You will get the following deprecation notice.

Function utf8_encode() is deprecated in ... on line ...
Function uft8_decode() is deprecated in ... on line ...

Instead of using the above functions you can use mbstring, iconv, and intl.

#6 Mbstring: Base64, Uuencode, QPrint, and HTML Entity encodings are deprecated

The mbstring() function helps you to work with the Unicode, HTML entities, and other legacy text encodings.

It is used to manipulate PHP strings containing multi-byte characters, such as Emojis, Asian characters, and thousands of other characters that are too large to fit into a single byte.

PHP 8.2 is deprecating the use of mbstring for the following encodings (the labels are case-insensitive):

  • BASE64
  • UUENCODE
  • HTML-ENTITIES
  • html (alias of HTML-ENTITIES)
  • Quoted-Printable
  • qprint (alias of Quoted-Printable)

mbstring() function will emit a deprecation notice from PHP 8.2 onwards when used to encode/decode any of the above.

Conclusion

In conclusion, PHP 8.2 brings significant improvements and new features for developers. The most notable new features are its standalone types, readonly properties, and various performance improvements.

These new additions build upon the significant improvements made in PHP 8.0 and PHP 8.1, making PHP 8.2 an essential update for all PHP developers.


Atatus: PHP Performance Monitoring

Atatus is an Application Performance Management (APM) solution that collects all requests to your PHP applications without requiring you to change your source code. However, the tool does more than just keep track of your application's performance. It monitors logs from all of your PHP applications and systems into a centralized and easy-to-navigate user interface, allowing you to troubleshoot faster.

We give a cost-effective, scalable method to centralized PHP logging, so you can obtain total insight across your complex architecture. To cut through the noise and focus on the key events that matter, you can search the logs by hostname, service, source, messages, and more. When you can correlate log events with APM slow traces and errors, troubleshooting becomes easy.

Try your 14-day free trial of Atatus.

Vaishnavi

Vaishnavi

CMO at Atatus.
Chennai

Monitor your entire software stack

Gain end-to-end visibility of every business transaction and see how each layer of your software stack affects your customer experience.