2022-02-06: Now updated for PHP 8.1.
PHP 8.0 was released at the end of 2020. It comes with an improved performance, some nice additions to the syntax and it also fixes some of the annoying quirks of its predecessors. Which is great … if it weren’t for that Huge Legacy Application you have to maintain, which is forever stuck on PHP 5.6 because it relies heavily on some long gone features. But it is not that bad, because it will soon be replaced by The New Application. At least that’s what we thought when PHP 7.0 came around.
There is also That Other Application which is already on 7.0. That means it has all the new and shiny features. Well, not exactly new, as PHP 7.0 was released in 2015! But somehow you still consider this to be modern because, you know, PHP 7! It’s a commercial software, newer versions are available. Sadly someone decided to make lots of changes to it. So no upgrades for us.
Luckily there is The New Application. A greenfield project. Well, kind of. It should replace both of the other applications. It also needs to work with the rest of the company infrastructure. So there are lots of constraints. But it is still new and fresh and state of the art. Well, at least it was, when it was started. It uses PHP7.3, which is only just out of the support period. Of course we could upgrade it. And we will. Soon.
On any given day there might be some fixes for the Huge Legacy System. Just before lunch you get a code review from a colleague who has the pleasure to support That Other Application. At lunch time you read about PHP 8’s additions to the syntax. Tonight you finally going to upgrade that pet project of yours. (Of course that’s what you keep telling yourself since last year ;-)) Lunch is followed by some meetings but at the end of the day you finally get to work on The New Application.
You are switching back and forth between half a dozen PHP releases, never quite sure about what feature you can and cannot use.
Help is coming
To fix this once and for all here is the PHP Feature Cheat Sheet covering the major changes introduced since PHP 7.0. Each version added some new syntax elements, others were deprecated or even removed. There were also lots of changes to the standard functions.
Note: This is not a comprehensive list of all the changes but highly biased based on my own experience.
The Cheat Sheet
The complete list of changes introduced with 7.0 can be found here.
To me the most important change to the language: starting with 7.0 the type system was greatly improved. You could already use class names, interfaces or
array for function arguments since PHP 5. 7.0 added scalar type declarations as well as return type declarations (typed class properties where introduced in 7.4).
Throwable was introduced as the base interface for anything that can be thrown. Ever wondered why some exception escaped your try-catch block? Most likely it was an
Error and you only mentioned
Exception in the catch part. Only
Throwable will really catch everything.
The null coalescing operator is a shorthand expression for using the ternary operator together with
isset. It returns the first operand if it exists and is not null, otherwise it returns the second operand.
The spaceship operator is used to compare two expressions. It will return -1 if the first operand is smaller than the second, 0 if they are equal and 1 if the first operand is bigger than the second. It can be used on numbers and strings.
The complete list of changes introduced with 7.1 can be found here.
One thing 7.0 was missing were nullable types. Starting with 7.1 parameters and return values can be marked as nullable. This means you could also pass (or return) null as well as the specified type.
Another addition to the type system: void functions. Functions can now be marked to return no value.
Class constant visibility
Not really a major new feature but as it is demanded by several code style tools it gets an honorable mention.
Multi catch exception handling
The ability to specify multiple exception types in one catch block allows for more flexibility and might also save some lines of code.
The complete list of changes introduced with 7.2 can be found here.
Object was added to the type system. It can be used for function parameters and return types.
The complete list of changes introduced with 7.3 can be found here.
Trailing Commas in Function Calls
The ability to add trailing commas allows for nicer diffs in multiline function calls. Which is also true for multiline arrays.
Continue Targeting Switch issues Warning
This change made the list because it affected composer itself as well as several prominent packages. I’ve seen this way to often.
The complete list of changes introduced with 7.4 can be found here.
Class properties can now be typed as well.
Arrow functions were introduced as a shorthand for anonymous functions aka closures. One slight difference: arrow function can always access variables from the parent scope. No need for the
Null coalescing assignment operator
As the name suggests, it combines the null coalescing operator with an assignment. See an example here.
The complete list of changes introduced with 8.0 can be found here.
This allows to pass arguments to a function based on the parameter name instead of the position. This means you can pass arguments in any order and you can skip arguments with default values. It also adds so meaning to the arguments.
Attributes allow us to add metadata on declarations. They can be evaluated using reflection. They are pretty similar to annotations but they are now part of the core language. That means the over better performance and are more reliable.
Constructor Property Promotion
A lot of constructors are pretty boring. They simply assign the parameters to the class properties. Constructor promotion offers a short-hand syntax for this.
Union type declaration allow us to use multiple different types. In early versions you would need to omit the type declaration in these cases and could only list the allowed types in the doc block. Now, this is part of the syntax.
This is somewhere between a
switch statement and a ternary expression mixed with arrow functions.
- It is an expression, so it evaluates to a value.
- Unlike switch it uses an identity check.
- There is no fall-through to later cases.
- Cases can be combined by listing multiple expressions separated by a comma
- There are no
- The expression must be exhaustive.
- There is also a
This comes in handy for chained method calls. If one part of the chain returns null, the rest is skipped and null is returned. In earlier versions this would result in an exception.
The complete list of changes introduced with 8.1 can be found here.
With enumerations you can replace all those constants and get validation out of the box.
Properties can be marked as readonly, which means they cannot be changed after being initialized.
New in initializers
This allows for using objects as default values.
Similar to union types, you can now specify type constraints as the intersection of types. Combining the two is not possible.
Never return type
This marks a function that will never return (because it throws an exception or uses
Can I use?
To make it even easier to figure out which feature you can use with which version, I added this handy table (slightly inspired by caniuse.com)
|Scalar type declarations||✅||✅||✅||✅||✅||✅||✅|
|Return type declarations||✅||✅||✅||✅||✅||✅||✅|
|Null coalescing operator (??)||✅||✅||✅||✅||✅||✅||✅|
|Spaceship operator (<=>)||✅||✅||✅||✅||✅||✅||✅|
|Class constant visibility||❌||✅||✅||✅||✅||✅||✅|
|Multi catch exception handling||❌||✅||✅||✅||✅||✅||✅|
|Trailing commas in function calls||❌||❌||❌||✅||✅||✅||✅|
|Continue targeting switch issues warning||❌||❌||❌||✅||✅||✅||✅|
|Null coalescing assignment operator||❌||❌||❌||❌||✅||✅||✅|
|Constructor property promotion||❌||❌||❌||❌||❌||✅||✅|
|String functions (||❌||❌||❌||❌||❌||✅||✅|
|New in initializers||❌||❌||❌||❌||❌||❌||✅|
|Never return type||❌||❌||❌||❌||❌||❌||✅|