PHP versions

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 amphpReactPHP 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.

Bild: https://www.php.net/releases/8.0/en.php

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

  • str_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.

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

Share this post

Leave a Reply

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

The reCAPTCHA verification period has expired. Please reload the page.