Table of Contents
Everywhere in software development we have versions which evolve over time to improve performance, fix security issues and add new functionality. The following list contains a short overview of the changes from PHP 7.1 to 8.1.
PHP 5.6 and 7.0 will not be included here because they are no longer being supported (php.net) (April 2019)
PHP 8.1
Native ENUM support
It now is possible to (similar to other modern programming languages like Kotlin, Rust or Swift) to define ENUMs (short for enumerated types).
A simple case of an ENUM is the following
enum TransportMode {
case Bicycle;
case Car;
case Ship;
case Plane;
case Feet;
}
and can be used like this
function travelCost(TransportMode $mode, int $distance): int
{ /* implementation */ }
$mode = TransportMode::Boat;
$bikeCost = travelCost(TransportMode::Bicycle, 90);
$boatCost = travelCost($mode, 90);
// this one would fail: (Enums are singletons, not scalars)
$failCost = travelCost('Car', 90);
But you can also set scalar values for each case inside the ENUM:
enum Metal: int {
case Gold = 1932;
case Silver = 1049;
case Lead = 1134;
case Uranium = 1905;
case Copper = 894;
}
BUT there are some rules you have to follow when setting scalar values:
- If you set one scalar value to 1 case then ALL cases need to have one. So either none have one or all have one, nothing in between.
- Scalar values (just like the case itself) need to be unique.
- The scalar values are read only
- To access the scalar value of an ENUM case you can do that via
Metal::Gold->value
The never
return type
Till now it was not possible to prevent functions from every returning anything. There was/is the void
type but it doesn’t care if you either exit
or just don’t return anything.
Forcing to exit
can now be done via the new never
return type:
function shutdown(): never {
exit();
}
But also implicit exit calls are allowed like:
function redirectToHome(): never {
redirect('/');
}
Fibers (Non-Blocking/asynchron PHP)
For all those developers who have doven into the World of e.g. NodeJS this topic may be a little strange. Basically PHP is written so all the lines of code are performed synchroniously. So like line 2 only gets executed after line 1 is done.
This however now can be changed via using fibers in PHP 8.1.
Asynchron PHP already has been somewhat available via external packages like amphp, ReactPHP or Guzzle but there was no standardized way of doing it (till now).
A good example using fibers can be found HERE
Readonly properties
Now you are able to set a property to be readonly. This means, that it only can be initialized once and can never be changed after that.
class Release {
public readonly string $version;
public function __construct(string $version) {
// Legal initialization.
$this->version = $version;
}
}
Whats the difference with defining a const
property?
public readonly string $version;
means, that the value of the property can differ from each object initialization of the type Release
.
But public const string $version;
means, that all objects created of the type Release
must have the same value.
PHP 8.0
JIT (Just in Time Compiler)
Without going too much into detail PHP 8.0 added a JIT Compiler which improves the performance of your PHP app “under certain conditions”. Unfortunately these conditions are not related to typicall CMS (like WordPress) usage and more “numeric” or “calulating” tasks.
Constructor property promotion
Till now properties needed to be initialized like so:
class Car {
public int $wheels;
public int $doors;
public function __construct(
int $wheels = 4,
int $doors = 5
) {
$this->wheels = $x;
$this->doors = $y;
}
}
But the exactly same logic can now be writte in a much smaller footprint:
class Carr {
public function __construct(
public int $wheels = 4,
public int $doors = 5
) {}
}
Union Types
The only union type present before PHP 8.0 was the?Type
to allow null values as well as the default Type
.
Otherwise you would have to add PHPDoc Union Types so static analysis tools like PHPStan understand the code better.
/**
* @property int|float $power
*/
class Car {
private $power;
/**
* @param int|float $power
*/
public function setPower($power) {
$this->power = $power;
}
/**
* @return int|float
*/
public function getPower() {
return $this->power;
}
}
Now you are abe to set these kind of Union Types directly in the property type, parameter type and return type.
class Number {
private int|float $number;
public function setNumber(int|float $number): void {
$this->number = $number;
}
public function getNumber(): int|float {
return $this->number;
}
}
PHP 8.0 in general focused on a more stricter typing system and typing features.
Named attributes
Defininig parameters inside your function required them to be in an order which seems logical so calling that functions is easier:
function calc($start, $end, $steps) {
...
}
so you could call it like that:
calc(10, 100, 5);
But now you can also do it like that:
calc(end: 100, start: 10, steps: 5);
Or even combine position oriented and named attributes like that:
calc(10, steps: 5, end: 100);
With this apporach you still have to position the not named attributes at the correct position!
Nullsafe-Operator
Sometimes you only wan’t call a specific method on an object if it is actually present/not null.
$result = null;
if($a !== null) {
$result = $a->b();
}
This can now be written like so:
$result = $a?->b();
So if $a
is null the methode b()
will not be called and $result
will be null
.
New string compare functions
I regularely have to perform string operations to check if e.g. a given string is present inside another or if one string starts with a specific string.
Till now you had to use the strpos()
function and depending on the return value build your logic which is not always very readable code.
With PHP 8.0 these pretty self explenatory functions have been introduced
- s
tr_contains( $haystack, $needle )
str_starts_with( $haystack, $needle )
str_ends_with( $haystack, $needle )
So you can write more readable and understandable code.
PHP 7.4
Spread-Operator for Arrays
Calling functions with a variable amount of arguments is nothing new for us.
function my_function(...$args) { var_dump($args); }
my_function('test', true, 123);
// Result
array(3) {
[0]=>
string(4) "test"
[1]=>
bool(true)
[2]=>
int(123)
}
But this functionality is now also available for array operations.
$bool_arr = [true, false];
$total_arr = ['text1', 123, ...$bool_arr , 456];
var_dump($total_arr );
// Result
array(5) {
[0]=>
string(5) "text1"
[1]=>
int(123)
[2]=>
bool(true)
[3]=>
bool(false)
[4]=>
int(456)
}
It is recommended to use this kind of array merging functionality instead of the typical array_merge()
function because it is more performant.
Arrow functions
One typicall example to use a arrow functions is to transform this
function cube($n){
return ($n * $n * $n);
}
$a = [1, 2, 3, 4, 5];
$b = array_map('cube', $a);
into this
$a = [1, 2, 3, 4, 5];
$b = array_map(fn($n) => $n * $n * $n, $a);
Null Coalescing Assignment Operator
PHP 7.0 already introduced a way to set a fallback value if a given variable is not set.
$this->request->data['comments']['user_id'] = $this->request->data['comments']['user_id'] ?? 'value';
But this can now be more condensed into this
$this->request->data['comments']['user_id'] ??= 'value';
Typed Class-Arguments
Now you can transform this
class User {
/** @var int $id */
private $id;
/** @var string $name */
private $name;
public function __construct(int $id, string $name) {
$this->id = $id;
$this->name = $name;
}
}
into this
class User {
public int $id;
public string $name;
}
The following types are being allowed:
- bool
- int
- float
- string
- array
- object
- iterable
- self
- parent
- Any class or interface
- nullable types (?type)
But neither void
nor callable
are allowed by definition!
Preloading
Without getting to complicated OPCache preloading improves PHP performance by always keeping the main libraries cached in the OPCache instead of reloading them every time a PHP process is being started.
This setting needs to be set in the php.ini
PHP 7.3
Trailing Commas are allowed in Calls
With PHP 7.3. it is now allowed to have a trailing comma even if it is the last parameter in a function call.
my_function(
$param1,
$param2,
);
JSON_THROW_ON_ERROR
Till now json_decode()
returns null
if an error occurs.
But null
can also be a valid result, which can lead to confusion.
So now you can check for json errors with these functions:
json_last_error()
- Returns (if present) the last error, which has occurred on the las encoding/decoding process for a JSON.
json_last_error_msg()
- Return “No error” if the encode /decode was a success and
FALSE
if there were problems.
- Return “No error” if the encode /decode was a success and
An anonymous user has written a very nice helper function on the json_last_error_msg() definition page on php.net:
<?php
if (!function_exists('json_last_error_msg')) {
function json_last_error_msg() {
static $ERRORS = array(
JSON_ERROR_NONE => 'No error',
JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
JSON_ERROR_STATE_MISMATCH => 'State mismatch (invalid or malformed JSON)',
JSON_ERROR_CTRL_CHAR => 'Control character error, possibly incorrectly encoded',
JSON_ERROR_SYNTAX => 'Syntax error',
JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded'
);
$error = json_last_error();
return isset($ERRORS[$error]) ? $ERRORS[$error] : 'Unknown error';
}
}
?>
Alternatively you an also solve that problem with a try-catch block:
try {
json_decode("{", false, 512, JSON_THROW_ON_ERROR);
}
catch (\JsonException $exception) {
echo $exception->getMessage(); // echoes "Syntax error"
}
is_countable function
Currently it is common to check a variable if it can be looped through a foreach with the following code:
$array = [1,2,3,4,5,6,7,8];
if(is_array($array) && sizeof($array) > 0){
foreach($array as $value){
}
}
But with PHP 7.3 you can write:
$array = [1,2,3,4,5,6,7,8];
if(is_countable($array)){
foreach($array as $value){
}
}
array_key_first(), array_key_last()
Till now it was not “easy” to get the first and last “key” of an array. But with PHP 7.3 you now have the functions array_key_first()
and array_key_last()
.
PHP 7.2
Native support for BMP image format
Since PHP 7.2 the GD extension allows to handle .bmp images.
Typ “object” bei Parameter- und Rückgabewerten einstellbar
A new type, object, has been introduced that can be used for parameter typing and return typing of any objects.
function test (object $a): object {
}
Enhancements to the EXIF extension
EXIF (Exchangeable Image File Format) is a standard to save metadata in image files.
Till now the automatically parsed EXIFF data for images files was very limited. With PHP 7.2 many EXIF formats from well known camera suppliers have been added. See HERE
Encrypted ZIP-Archives
With PHP 7.2 you can now create ZIP archives with a password protection.
PHP 7.1
“Nullable types”
function test1(?array $a) {
}
function test2($a): ?array {
}
The first function (test1) defines, that the first parameter can have the type “Array”, but can also be “null” (? before the array)
The second function (test2) defines, that the return value can have the type “Array”, but also “null” too.
Without the prefixed ? the function test1 called with a parameter “null” or the second function test2 with a return value of “null” would lead into a “Fatal Error” when executing that code.
Array and list have same functionality
Old Code:
$array = array(0 => 'a', 1 => 'b');
list($a, $b) = $array;
// $a is = 'a'
// $b is = 'b'
New Code:
$array = array(0 => 'a', 1 => 'b', 2 => 'c');
[$a, $b] = $array;
// $a is = 'a'
// $b is = 'b'
list(1 => $b, 2 => $c) = $array;
// same as above
[1 => $b, 2 => $c] = $array;
Visibility of constants in classes
As already common in other object oriented programming languages you can now set “visibilities” for class constants.
public
Access to variable allowed from everywhere.protected
Access to variable only allowed in its own class AND all extended classes.private
Access to variable only allowed in its own class.
class test {
const PUBLIC1 = 'TEST';
public const PUBLIC2 = 'TEST';
protected const PROTECTED = 'TEST';
private const PRIVATE = 'TEST';
}
Multi catch exception handling
You can now have multiple exceptions in one try-catch block.
try {
throw new Exception('Fehler');
} catch (Exception | AndererExceptionTyp $catchedException) {
var_dump($catchedException);
}
mcrypt extension deprecated => use OpenSSL
The functions of the “mcrypt” extension (function names all start with “mcrypt_”) will be marked as “deprecated” markiert and therefore produce a line in the error.log.
Use the OpenSSL extension as a replacement.
Sources