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:
We all have so many Value Objects and Entities. And each of them looks like this:
PHP 8.0 and Nikita Popov gave us freedom from properties boilerplate for all simple cases, when you set your properties in constructor:
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.
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.
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.
From now on we can catch even more bugs on early stages.
$emptyArray will be empty, that you have ValueError Exception, that extends Exception:
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
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.
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:
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:
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.
From 8.0 you can do this:
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'.
Personally, one of my favorites. No more
if or strange looking chains with null coalescence operators.
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.
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
match may also contain multiple comma-separated expressions, that give us opportunity to have more shortened syntax:
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:
str_ends_with() are here for you if you need even more precise search.
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:
$object::class is a new
Thanks to Nikita Popov, now instead of remembering another internal function, we can just get the class for an object as simple as that
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!