PHP 8 New Feature You Need to Know as PHP Developer

Reynald
9 min readMar 11, 2021
php 8 logo

By the time I wrote this article, it has been 4 months since the release of php 8 which is 26 November 2020. It’s hard to believe, but the new version already in the corner. As part of this release, you will benefit from performance improvements — thanks to the new JIT Compiler. But you will also enjoy useful new operators and types, attributes, match expression and so much more. In this article, I will show you what you need to know about the new features and I will explain it in detail.

1. The Null Safe Operator

<?phpclass User {
public function profile()
{
return new Profile;
}
}
class Profile {
public function employment()
{
return 'Manager';
}
}
$user = new User();
echo $user->profile()->employment();
// result 'Manager'

Let’s take a look at the php code above. If we give it a run code above we will get echoed result Managerbut that will be working for php 7 as well. However, sometimes we would find the method profile() is running some kind of DB query to fetch Profile, and when it can’t find Profile it will return null , this can often be a trap we usually run into, and if we trying to give it a run we will get an error Call to a member function employment() on null.

So what we do in these cases? Traditionally we would try something like this.

$user = new User;
$profile = $user->profile();
if ($profile) {
echo $profile->employment();
}

I am sure you have done something similar to this. But in php 8 it’s a little bit cleaner. We could change it into something like this.

$user->profile()?->employment()

So this ?-> is our new operator, the Null Safe Operator. And if you trying to give it a run it will return the same echoed result Manager , but on the conditions that method profile() return nullit doesn’t blow up an error instead, it will be return null

2. Match Expression

The match expression is similar to php switch statement. However, it’s more like key-value pairs. Unlike switch, the comparison is an identity check (===) rather than a weak equality check (==). Take a look at the example below.

<?phpclass Car {}$obj = new Car();// using traditional switch
switch (get_class($obj)) {
case 'Car':
$type = 'this is car';
break;
case 'Truck':
$type = 'this is truck';
break;
}
echo $type;
// using new match expression
$type = match (get_class($obj)) {
'Car' => 'this is car',
'Truck' => 'this is truck'
}
echo $type;

If you give it a run, you will get the exact same thing. But notice how much cleaner this is, we only have to assign the $type variable once, and of course, we don’t need to use the break keyword. And that’s really it.

3. Constructor Property Promotion

Let’s take a look at the example code below.

<?phpclass User
{
protected $name;
public function __construct($name)
{
$this->name = $name;
}
}
class Service
{
protected $name;
public function __construct($name)
{
$this->name = $name;
}
}
class Register
{
protected User $user;
protected Service $service;
public function __construct(User $user, Service $service)
{
$this->user = $user;
$this->service = $service;
}
}
$user = new User('Jane');
$service = new Service('Premium');
$register = new Register($user, $service);
var_dump($register);

Notice how many$user I add in the Register class just to set $this->user in the class. Yes it’s 4 times, the same goes with $service and $name for Service & User class. If you give it a run code above, you will get var_dump of Register class object. Of course, this will also work back in php 5, nothing really new here. But again what is new is the concept of property promotion. So here’s the basic idea, php can figure out what you trying to do here, so if we give a little bit more information such as protected $name php can do the rest of the assignment. Now take a look at the updated code below with constructor property promotion.

<?phpclass User
{
public function __construct(protected $name)
{
//
}
}
class Service
{
public function __construct(protected string $name = "Basic")
{
//
}
}
class Register
{
public function __construct(
protected User $user,
protected Service $service
) {
//
}
}
$user = new User('Jane');
$service = new Service('Premium');
$register = new Register($user, $service);
var_dump($register);

If you try to run the code above you will get the exact same thing as the previous example. On top of that, you can also declare type and default in the process. Notice how much cleaner it is to use constructor property promotion. A couple of caveats to be aware of, you can set default but there are limited for primitive, so you can’t provide any expression there. If you need to perform any validation or check you can do that in the constructor body.

4. Allow ::class on $object

If you working on php long enough I believe you have tried doing class syntax like this Staff::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::classyou will get an error

Cannot use ::class with dynamic class name

However, in php 8 you can! You can assign a class into a dynamic php variable and use class syntax.

<?php$object = new Staff;// usually in php 7 you will use get_class($object)
// to get the same result
// however this will work in php 8
switch ($object::class) {
case 'Staff' :
$className = 'This is staff';
break;
case 'Employee' :
$className = 'This is employee';
break;
}
var_dump($className);

5. Named Parameters

Named parameters allow us to call a function or method and then pass the argument based upon the parameter name rather than the order it occurs. Now take a look at the code below

<?phpclass LoanShark {
private $name;
private $age;
private $money;
private $gender;
public function __construct($name, $age, $money, $gender)
{
$this->name= $name;
$this->age = $age;
$this->money = $money;
$this->gender = $gender;
}
}
$loanShark = new LoanShark(
'Kazuma Kiryu',
24,
100000,
'Male'
);
var_dump($loanShark);

If you try to run the code above you will get var_dump result of LoanShark class object, exactly what you expect. But what often happens is you will return to this code six months from now, you see this number 10000 or 24 and you think to yourself I have no idea what this number refer to. So you endup clicking through the underlying class and you check that way. However, in php 8 you can reach for named parameters, now take a look at the code below.

$loanShark = new LoanShark(
name: 'Kazuma Kiryu',
age: 24,
money: 100000,
gender: 'Male'
);

Isn’t that nice? Obviously and you know what, if you used named parameters here the parameter order is irrelevant. That means if you put the name in the last parameter order or put money in the beginning, it still works.

What do you think about these Named Parameters? Do you see any downside? It does solve the readability problem. However, one thing that you need to be aware of, if you adopt Named Parameters you are now coupling your code to the variable or parameter name themself. For example imagine if the LoanShark class here is coming from 3rd party packages and at some point the maintainer refactoring their code and they think this parameter $money should be changed to $dollar so they go ahead and update this.

<?phpclass LoanShark
{
private $name;
private $age;
private $dollar;
private $gender;
public function __construct($name, $age, $dollar, $gender)
{
$this->name= $name;
$this->age = $age;
$this->dollar = $dollar;
$this->gender = $gender;
}
}
$loanShark = new LoanShark(
name: 'Kazuma Kiryu',
age: 24,
money: 100000,
gender: 'Male'
);
var_dump($loanShark);

With the named parameters this is now technically a breaking change. Think about it, the maintainer released a patch release, you pulled in, then you run some code or tests, and everything blows up. So this is what I mean by

your code is now coupled with the names themself, so you have to keep this in sync.

So as it turns out developers come out both side of this conversation and you need to decide for yourself or your team which one make sense. The takeaways are be very cautious when using named parameters, or another option is don’t use named parameters at all. Somebody with the arguments against this would say

The fact that you want to reach for these named arguments is probably an indication that the class already doing too much. So often you will find it usefull if the class accept 5 or 6 arguments. Well maybe the class should not accept 6 arguments and if it did you would not get much benefit from named parameters.

Well but you know what, I think that might be coming from someone with the simplistic approach, the reality is there are situations where it does make sense to accept that many arguments.

6. New String Helpers

Next is we got new 3 string helpers!

(1) str_starts_with

This helper will return boolean true if string starts with the given keyword, and false if it doesn’t match.

$hash = 'key_123asd456qwer';
$result = str_starts_with($hash, 'key_');
// you will get result true
var_dump($result);

(2) str_ends_with

This helper is similar with str_starts_with but instead, it’s checking at the end of the string.

$hash = '123asd456qwer_key';
$result = str_ends_with($hash, '_key');
// you will get result true
var_dump($result);

(3) str_contains

This helper is my favorite and it’s pretty straightforward. It checks whether a given keyword exists in the string.

$url = 'http://acme.com?premium=1';
$result = str_contains($url, '?');
// you will get result true
var_dump($result);

7. Weak Map

A weak map is effectively a key-value store very much like an array, except your key is an object, so it allows you to associate an object with some piece of data. Two things that weak map solve is:

  • (1) Week map object allows us to use the object as a key association.

Now take a look at the code below for the example.

<?php$weakMapObj = new WeakMap();
$normalObj = new stdClass();
// this array will not work with normal Object
[
$normalObj => 'FurBoll'
]
// this array will work because it use WeakMap Object
[
$weakMapObj => 'Kanpai'
]
  • (2) Allows For Garbage Collections

Now this is much lower level and generally as PHP Developer you won’t need to think about it, but if you are working on asynchronous applications with PHP, or you have long-running processes where you have to be careful, this is something you need to be aware of.

In the past, if you did want to associate an object with a piece of data you can use SplObjectStorage(). Now take a look at the code below for the example using SplObjectStorage() . In this example I assigned object instantiated with SplObjectStorage() into normal stdClass object as key for storing string foobor and then i unset the object.

$map = new WeakMap();
$obj = stdClass();
$store = new SplObjectStorage();
$store[$obj] = 'foobor';// first var_dump
var_dump($store);
// then i unset the $obj
unset($obj);
// second var_dump
var_dump($store);

If you try to run the code above and see the result you’ll notice the second var_dump would not clean up and we still have a reference to the object. These approach restrict garbage collection and prevent object cleanup after unsetting the object.

// second var_dump outputobject(SplOBjectStorage)#2 (1) {
["storage":"SplObjectStorage":private]=> array(1) {
["00000051f8da760000000e78b51"] => array(2) {
["obj"]=> object(stdClass)#1 (0) {
}
["inf"]=> string(6) "foobor"
}
}
}

This is what exactly Weakmap solve. Now take a look at the example below.

$map = new WeakMap();
$obj = stdClass();
$store = new SplObjectStorage();
$store[$map] = 'foobor';// first var_dump
var_dump($store);
// then i unset the $map
unset($map);
// second var_dump
var_dump($store);

In this example I replace the object using WeakMap() and if you see the result you’ll notice the $map reference is gone on second var_dump. And that’s pretty much about Week Map.

8. Union Type

Although i never used it in PHP version 7.4 Union Type did exist before version 8 in it’s own form. Despite it only have 2 kind of types which is Nullable type and iterable type. Take a look at the Example class below.

<?php class Example {    // this is nullable type example in php 7.4
// this is equally string|null in php 8
public function doSomething(?User $user) {
} // this is iterable type example in php 7.4
// this is equally array|Traversable in php 8
public function doElse(iterable $array)
{
}
}

In PHP 8 using | on each types you can declare any number of types for the property, argument, and return types. You can completely get rid of @var, @param, @return in PHP doc comment now in favor of the types enforced in the code itself.

<?phpclass User {    private int|float $foo;    public function cancel(User|string|null|array $user): array|int
{
}
}

Well that’s pretty much about this article, if you interested in complete release info you can take a look at https://www.php.net/releases/8.0/en.php. I hope this article can be helpful on your day to day developer work and get better understanding of PHP 8 new feature.

--

--

Reynald

I am a fullstack web developer from Indonesia.