What's New in PHP 8.1?

What's New in PHP 8.1?

If you are still using PHP 7 then this article is for you. There is some highly-requested functionality built into PHP 8, specifically PHP 8.1 that you need to know. It will make your programming life much easier.

View This On YouTube

In this article, I am going to show you the PHP 7 way, then I am going to show you the PHP 8 way. Let's cut to the chase.

NULLSafe Operators

If you've used the null coalescing operator in the past, you probably also noticed its shortcomings: null coalescing doesn't work on method calls.

The nullsafe operator provides functionality similar to null coalescing, but also supports method calls.

The NULLSafe Operator will allow you to check for nulls on a method so there is no need for an IF statement within the response itself. Instead you would simple add ? after the method to check it for a null return.

PHP 7

class User {
    public function getProfile() {
        return null;
        return new Profile;
    }
}

class Profile{
    public function getTitle() {
        return null;
        return "Software Engineer";
    }
}

$user = new User;
$profile = $user->getProfile();

/*
pre null coalescing
if ($profile) {
    if($profile->getTitle()) {
        echo $profile->getTitle();
    }else{
        echo 'Not provided';
    }
}
*/

/* post null coalescing */
echo ($profile ? ($profile->getTitle() ?? 'Not provided') : 'Not provided');

PHP 8

class User {
    public function getProfile() {
        //return null;
        return new Profile;
    }
}

class Profile{
    public function getTitle() {
        //return null;
        return "Software Engineer";
    }
}

$user = new User;
$profile = $user->getProfile();

// uses NULL Operator after the getProfile() method
echo $user->getProfile()?->getTitle() ?? 'Not provided';

Constructor Property Promotion

Property promotion allows you to combine class fields, constructor definition and variable assignments all into one syntax, in the construct parameter list.

Ditch all the class properties and the variable assignments, and prefix the constructor parameters with public, protected or private. PHP will take that new syntax, and transform it to normal syntax under the hood, before actually executing the code.

NOTE: Promoted properties can only be used in constructors.

PHP 7

class Signup {
    protected UserInfo $user;

    protected PLanInfo $plan;

    public function __construct(UserInfo $user, PlanInfo $plan) {
        $this->user = $user;
        $this->plan = $plan;
    }
}

class UserInfo {
    protected string $username;

    public function __construct($username) {
        $this->username = $username;
    }
}

class PlanInfo {
    protected string $name;

    public function __construct($name = 'yearly') {
        $this->name = $name;
    }
}

$userInfo = new UserInfo('Test Account');
$planInfo = new PlanInfo('monthly');

$signup = new Signup($userInfo, $planInfo);

PHP 8

class Signup {
    public function __construct(protected UserInfo $user, protected PlanInfo $plan) {
    }
}

class UserInfo {
    public function __construct(protected string $username) {
    }
}

class PlanInfo {
    public function __construct(protected string $name = 'yearly') {
    }
}

$userInfo = new UserInfo('Test Account');
$planInfo = new PlanInfo('monthly');

$signup = new Signup($userInfo, $planInfo);

Match Expressions

PHP 8 introduces the new match expression. A powerful feature that will often be the better choice to using switch.

NOTE: Match will do strict type checks instead of loose ones. It's like using === instead of ==.

PHP 7

$test = 'Send';

switch ($test) {
    case 'Send':
        $type = 'send_message';
        break;
    case 'Remove':
        $type = 'remove_message';
        break;
}
echo $type;

PHP 8

$test = 'Send';

$type = match ($test) {
    'Send'=>'send_message',
    'Remove'=>'remove_message'
};

echo $type;

$object::class

It is now possible to fetch the class name of an object using $object::class. The result is the same as get_class($object).

If you working on php long enough I believe you have tried doing class syntax like this Class::method or get_class(new Class()) to fetch a class name as a string. However, if you assign a dynamic class name into a variable and use class syntax like this $object::class you will get an error "Cannot use ::class with dynamic class name". In PHP 8, you can.

PHP 7 N/A, shows error

PHP 8

class Send{}
$message = new Send();

$type = match ($message::class) {
    'Send'=>'send_message',
    'Remove'=>'remove_message'
};

Named Parameters/Arguments

Named arguments allow you to pass input data into a function, based on their argument name instead of the argument order. This type of functionality is good for keeping tracking of what means what. If you go back to your code and see where you are a calling a method, you may get confused as to what you are calling.

Named parameters help prevent this. They give you the ability to tell your future self what type of variables you are assigning to the method without having to dig through your code and figure out what it does.

NOTE: If your argument names change in the method, it will break your code as the named parameter is no longer valid.

PHP 7

class Invoice {
    private $customer;
    private $amount;
    private $date;

    public function __construct($customer, $amount, $date) {
        $this->customer = $customer;
        $this->amount = $amount;
        $this->date = $date;
    }
}

$invoice = new Invoice(
    'Test Account', 
    100, 
    new DateTime
);

PHP 8

class Invoice {
    public function __construct(private string $customer, private int $amount, private dateTime $date) {}
}

$invoice = new Invoice(
    customer: 'Test Account', 
    amount: 100, 
    date: new DateTime
);

String Helpers

Have you ever wanted to find a string in a string in PHP? Most likely you have and most likely you know it is a pain since prior to PHP 8, there was not a lookup function for this purpose even thouh it is one of the most request items for PHP since it was created.

In the past, you need to understand how the math worked and match certain parameters, well, that is now gone and the future of string matching is here.

PHP 7

$string = 'inv_1234_mid_67890_rec';
echo 'Starts with inv_: '.(substr_compare($string, 'inv_', 0, strLen('_inc')) === 0 ? "Yes" : "No");
echo 'Ends with _rec: '.(substr_compare($string, '_rec', -strLen('_rec')) === 0 ? "Yes" : "No");
echo 'Contains _mid_: '.(strpos($string, '_mid_') ? "Yes" : "No");

PHP 8

$string = 'inv_1234_mid_67890_rec';
echo 'Starts with inv_: '.(str_starts_with($string, 'inv_') ? "Yes" : "No");
echo 'Ends with _rec: '.(str_ends_with($string, '_rec') ? "Yes" : "No");
echo 'Contains _mid_: '.(str_contains($string, '_mid_') ? "Yes" : "No");

Union and Pseudo Types

In versions prior to PHP 8.0, you could only declare a single type for properties, parameters, and return types. PHP 7.1 and newer versions have nullable types, which means you can declare the type to be null with a type declaration similar to ?string or by using PHPDoc comments.

From PHP 8.0, you can declare more than one type for arguments, return types, and class properties.

PHP 7

class Foo {

    public function bar(?Foo $foo) {
        echo 'Complete';
    }
}

$one = new Foo;
$two = new Foo;

$two->bar($one);
$two->bar(null);
// string fails as it is expecting Foo or Null
$two->bar('Test');

PHP 8

class Foo {

    public function bar(Foo|string|null $foo) {
        echo 'Complete';
    }
}

$one = new Foo;
$two = new Foo;

// everything works
$two->bar($one);
$two->bar(null);
$two->bar('Test');

Conclusion

What is your favorite new feature in PHP 8 and PHP 8.1? Mine is the string helpers and match functions because I already use the older version in almost every project I create in PHP. I hope this helps you make the switch to PHP 8.