Saturday, November 23, 2024
HomeEveryday WordPressWhat's New & What's Changed In the Latest Release

What’s New & What’s Changed In the Latest Release


PHP 8.3 was released on schedule on November 23 and packs many new features and improvements since the launch of PHP 8.2. Even though it’s officially considered a minor release, some of the changes in 8.3 might directly affect your work with PHP — perhaps helping you code faster and with fewer bugs.

Let’s dive in and look at the big — and sometimes not-so-big — changes that come with this latest release.

New Features and Improvements in PHP 8.3

Let’s start by exploring the PHP 8.3 features that grab most of the headlines.

Typed Class Constants

The ability to declare types for class properties has been available to us since PHP 7.4. However, despite numerous tweaks to PHP typing over the years, it hasn’t extended to constants — until now.

Class constants — and that also includes interface, trait, and enum constants — can be typed in PHP 8.3, making it less likely that developers will stray from the intention behind a constant’s initial declaration.

Here’s a basic example using an interface:

// Legal:
interface ConstTest {
    // Declared type and value are both strings
    const string VERSION = "PHP 8.3";
}

// Illegal:
interface ConstTest {
    // Type and value mismatch in this initial declaration
    const float VERSION = "PHP 8.3";
}

The real value of those typed class constants is revealed when working in classes derived from the base declarations. While a child class can frequently assign a new value to a constant, PHP 8.3 can help prevent accidentally changing its type so that it becomes incompatible with the initial declaration:

class ConstTest {
    const string VERSION = "PHP 8.2";
}

class MyConstTest extends ConstTest {

    // Legal:
    // It's OK to change the value of VERSION here
    const string VERSION = "PHP 8.3";

    // Illegal:
    // Type must be declared if it was specified in the base class
    const VERSION = "PHP 8.3";

    // Illegal:
    // In this case, we can't change the type declared in the 
    // base class, even if the new type and its value are compatible.
    const float VERSION = 8.3;
}

Keep in mind that the type assigned to a class constant can vary when “narrowing” multiple types or using an otherwise compatible type:

class ConstTest {
    const string|float VERSION = "PHP 8.2";
}

class MyConstTest extends ConstTest {

    // Legal:
    // Here, it's OK to narrow the type declaration to string or float
    const string VERSION = "PHP 8.3";
    const float VERSION = 8.3;

    // Legal:
    // Value could be an int, but it's compatible with float 
    const float VERSION = 8;

    // Illegal:
    // We can't widen the type options here to include int
    const string|float|int VERSION = 8;
}

Two types supported for other properties when validating return values — void and never — are not supported as class constant types.

A New json_validate() Function

When working with JSON-encoded data, it’s nice to know if the payload is syntactically valid before attempting to do something with it.

In previous releases of PHP, developers have used the json_decode() function and checked for errors while that function attempts to turn JSON data into associative arrays or objects. PHP 8.3’s new json_validate() function does the error checking without using all the memory required to build those array or object structures.

So, in the past, you might have validated a JSON payload something like this:

$obj = json_decode($maybeJSON);

if (json_last_error() === JSON_ERROR_NONE) {
    // Probably do something with $obj   
}

If you aren’t going to do something right away with $obj in the example above, that’s a lot of resources used just to confirm the validity of the original JSON payload. In PHP 8.3, you can do something like this and spare some memory:

if (json_validate($maybeJSON) {
    // Do something with $maybeJSON   
}

Note: It doesn’t make a lot of sense to use json_validate() and then immediately run the data through json_decode(), using decode’s memory resources anyway. You are more likely to use the new function to validate the JSON before storing it somewhere or delivering it as a request response.

Deep Cloning of readonly Properties

The ability to declare individual class properties as readonly appeared in PHP 8.1. PHP 8.2 introduced the ability to assign that attribute to an entire class. However, many developers felt the constraints imposed when working with classes containing such properties got in the way of useful programming.

An RFC for modifying readonly behavior made two proposals:

  1. Allow classes that are not readonly to extend classes that are
  2. Allow readonly properties to be reinitialized when cloning

It’s the second proposal that has made it into PHP 8.3. The new approach allows instances of a class with readonly properties to be reinitialized within the __clone magic method (including via functions invoked from within __clone).

This code example from the RFC shows how it works:

class Foo {
    public function __construct(
        public readonly DateTime $bar,
        public readonly DateTime $baz
    ) {}
 
    public function __clone() {
        // $bar will get a new DateTime when clone is invoked
        $this->bar = clone $this->bar; 

        // And this function will be called
        $this->cloneBaz();
    }
 
    private function cloneBaz() {
       // This is legal when called from within __clone
        unset($this->baz); 
    }
}
 
$foo = new Foo(new DateTime(), new DateTime());
$foo2 = clone $foo;

New #[Override] Attribute

When implementing interfaces in PHP, programmers provide detailed functionality for methods named in those interfaces. When creating an instance of a class, programmers can override a parent method by creating an alternate version with the same name and a compatible signature in the child.

One problem is that programmers might think they are implementing an interface method or overriding a parent method when they are not. They might be creating an entirely separate beast because of a typo in the name of the child-class method or because methods have been removed or renamed in the parent code.

PHP 8.3 introduces the #[Override] attribute to help programmers make it clear that a method must have some lineage within the code.

Here’s a basic example:

class A {
    protected function ovrTest(): void {}
}

// This will work because ovrTest() 
// can be found in the parent class
class B extends A {
    #[Override]
    public function ovrTest(): void {}
}

// This will fail because ovrBest() 
// (probably a typo) is not in the parent
class C extends A {
    #[Override]
    public function ovrBest(): void {}
}



Source link

RELATED ARTICLES
Continue to the category

LEAVE A REPLY

Please enter your comment!
Please enter your name here


Most Popular

Recent Comments