DEV Community

loading...
Cover image for Cutting Edge: Using PHP 8.0 in Enterprise

Cutting Edge: Using PHP 8.0 in Enterprise

Anastasiia Lysenko
Experienced developer, team lead and architect, who see the patterns everywhere around the world and love to keep code in well-documented, clean and organized shape.
・6 min read

In this article I am planning to describe perks and features of PHP 8.0, that we are already using or going to use in the one of our new microservices in existing chatbot messaging project.

As many of PHP developers, my team can't wait to try new version of PHP as soon as possible. So, right in time when new microservice got from strategy planning stage to solution architecture choices, I already knew what it's going to be. Long story short, Symfony 5 and PHP 8.0 were the winners. Here I should mention, that we use microservices coupled with DDD business principles and Onion architecture in almost each of them. Here you can dive in. This strong decoupling made this 'on edge move' possible in such short time.

Meanwhile, what we like and use from the new features:

Duplicated Properties Are Dead! Long Live The Constructor

We all have so many Value Objects and Entities. And each of them looks like this:

Alt Text

PHP 8.0 and Nikita Popov gave us freedom from properties boilerplate for all simple cases, when you set your properties in constructor:

Alt Text

Nice and easy. We use it with all our new value objects and entities, as well as other resembling classes.
Be careful: those properties are not allowed in abstract classes and interfaces as well as callable and nullable properties. Surely, you can't declare them twice: as properties and in constructor.

Let's make a Union with Types

It's definitely the blast! I personally voted for them, because it's such a strong adding to 'typed properties' from the one side and flexibility from the other.

Alt Text

Either you need different types of a number, string, arrays or interfaces: you can now describe all of possible types as input parameters in your methods, class variables and method return. This way you enforce types, so mistakes can be caught early, types are checked during inheritance, enforcing the Liskov Substitution Principle (L from SOLID). You can freely use Reflection, because union types are available through Reflection. The last, but not least, the syntax needs less amount of efforts, than phpdoc.

So, the question is: what types can't we have as 'union typed'. The following list would be the answer:

  • The void type could not be part of a union, as void means that a function does not return any value.
  • The nullable type notation (?Type) is allowed, so we can do Type|null, but we are not allowed to include the ?Type notation in union types (?Type1|Type2 is not allowed and we should use Type1|Type2|null instead).

As many internal functions include false among the return types, the false pseudo-type is also supported for backward compatibility.
That capability was only added to support legacy code. So, we are not planning to use it for any new code, so should not anyone.

ValueError Exception

From now on we can catch even more bugs on early stages.

Alt Text

If $emptyArray will be empty, that you have ValueError Exception, that extends Exception:

Alt Text

PHP throws this exception every time you pass a value to a function, which has a valid type, but can not be used for the particular operation (for example, empty arrays, negative number in case with json_decode, etc.).

Sure, we will not catch this specific Error each time, but before PHP 8, all those wrong cases throws just a warning, so it was not possible to catch it with Exception, as it is now.

Say hello to Throw as an expression

Alt Text

Finally, we can have more readable 'possibly wrong' code with even less amount of 'exception handling' code.

For those of you, who does not need en $exception as variable in catch block, it's now possible to not define it:

Alt Text

String it

PHP 8 gives us a Stringable interface that corresponds to an object having the __toString() magic method.

A class may implement a Stringable interface that defines a method public function __toString(): string. Useful fact: if it doesn’t, but still implements that method, the engine will add the method and return type automatically. So, we can now check type in the union type, for example, like this:

Alt Text

Static in return

Many of us get into the situations, when we need to call class methods in chain and get the result from the last one, for example. All those years of JS jokes saying out loud at last gives us chained methods with late static binding from now on. Self, parent and static can now be used in different usecases with chained methods.

Do not mix with mixed

From 8.0 you can do this:

Alt Text

Maybe, it's necessary in some rare cases, but even those cases we refactored to union types in our project. Try to avoid this 'type' as much as possible. Personally, I think it's equal to 'no type at all'.

Safe and sound with null

Alt Text

Personally, one of my favorites. No more if or strange looking chains with null coalescence operators.

We have a match!

And my second favorite is match. It is pretty similar to well-known switch but with safer semantics and allowing to return values. So you don't need the variable for it anymore.

Der Teufel steckt im Detail.

While switch compares values loosely (==) potentially leading to unexpected results, match comparison is an identity check (===). I think, it's a huge difference and we are definitely will use match instead of switch.

Alt Text

The match may also contain multiple comma-separated expressions, that give us opportunity to have more shortened syntax:

Alt Text

More functions, we need more functions

str_contains will definitely come in handy for almost all of us.

Say 'no' to every PHP developer nightmare with looking for a match in string. Everytime it's strstr combined with strpos and checking to bigger than zero. Say 'yes' to one simple function instead of it:

Alt Text

str_starts_with() and str_ends_with() are here for you if you need even more precise search.

You name it

I see the main advantage of named arguments is that they allow to specify only arguments we want to change. So it's not necessary to specify default arguments if we don’t want to overwrite default values. The following example makes it clear:

Alt Text

Sugar, baby

$object::class is a new get_class().

Thanks to Nikita Popov, now instead of remembering another internal function, we can just get the class for an object as simple as that ::class.


What we are definitely planning to use attributes. As for well-known new feature JIT, I do not see the extreme necessary or gaining some big value for our project in using it at the moment. We have opcache enabled, as it is by default and using Go for sockets, long time parsers, etc. But, who knows, maybe we'll try it later.

As conclusion, I should say, that PHP 8.0 got awesome changes and my team and I are so excited to try it in a real live project. We hope, that our code transforms to more clean and readable shape as well as gains performance and usability.

Time to try it by yourself :)


Keep your code clean and clear and yourself safe and sound!

Discussion (0)