Cutting Edge: Using PHP 8.0 in Enterprise
Anastasiia Lysenko
Posted on February 26, 2021
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:
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.
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.
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.
If $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 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
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:
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:
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:
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
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
.
The match
may also contain multiple comma-separated expressions, that give us opportunity to have more shortened syntax:
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:
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:
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!
Posted on February 26, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.