What's new in PHP 8: New Features and Improvements

PHP
Harish Kumar · · 5576 Views
PHP 8 Improvements and new features

PHP 8 Improvements and new features

PHP 8.0 is a major update of the PHP language. It contains a range of new features and optimizations such as the JIT compiler, union types, attributes, constructor property promotion, match expression, nullsafe operator, JIT, and improvements in the type system, error handling, and more.

Union Types (RFC)

A union type accepts values of multiple different types, instead of a single one. PHP is a dynamically typed structure, So union types are extremely helpful in many places.

The syntax for Union types are T1|T2|... (eg. int|float $price).

In PHP 7.x

// in PHP7.x
class Order {
  /**
   * @var int|float $total
   */
  private $total;

  /**
   * @param int|float $total
   */
  public function setTotal($total) {
    $this->total = $total;
  }

  /**
   * @return int|float
   */
  public function getTotal() {
    return $this->total;
  }
}

In PHP 8

//php8
class Order {
  private int|float $total;

  public function setTotal(int|float $total) : void {
    $this->total = $total;
  }

  public function getTotal() : int|float {
    return $this->total;
  }

}

// $order =  new Order();
// $order->setTotal(100);
// var_dump($order->getTotal());

WeakMap (RFC)

Weak maps allow creating a map from objects to arbitrary values (similar to SplObjectStorage) without preventing the objects that are used as keys from being garbage collected. If an object key is garbage collected, it will simply be removed from the map.

It is utilized for storing references. It permits us to make a map from objects to arbitrary values without preventing the objects that are utilized as keys from being garbage collected.

In long-running processes, this would prevent memory leaks and improve execution.

Here is an example.

<?php

class FooBar {
    public WeakMap $cache;
    
    public function __construct() {
    	$this->cache = new WeakMap();
    }
 
    public function getSomethingWithCaching(object $obj) {
        return $this->cache[$obj] ??= $this->computeSomethingExpensive($obj);
    }
    
    public function computeSomethingExpensive(object $obj) {
		dump("I got called");
		return rand(1, 100);
    }
}

$cacheObject = new stdClass;

$obj = new FooBar;
// "I got called" only will be printed once
$obj->getSomethingWithCaching($cacheObject);
$obj->getSomethingWithCaching($cacheObject);

dump(count($obj->cache));

// When unsetting our object, the WeakMap frees up memory
unset($cacheObject);

dump(count($obj->cache));

exit;

New `static` return type (RFC)

Although self return was already possible, static was not a legitimate return type until PHP 8. It's a function that will be useful to numerous developers, thinking about the dynamically typed nature of PHP.

class Foo
{
    public function test(): static
    {
        return new static();
    }
}

New mixed type (RFC)

PHP 8 presents another type called mixed that you can utilize. A type of mixed would be equivalent to array|bool|callable|int|float|null|object|resource|string.

<?php

function debug_function(mixed ...$data) {
	dump($data);
}

debug_function(1, 'string', []);

$object::class - Class name literal on object (RFC)

The $object::class used to get the name of the class of a given object. $object::class gives a similar outcome as get_class($object). If $object isn't an object, it throws a TypeError exception.

<?php

$object = new stdClass;
var_dump($object::class); // "stdClass"
 
$object = null;
var_dump($object::class); // TypeError

New `Stringable` interface (RFC)

The Stringable interface can be utilized to type-hint whatever executes __toString(). If a class has __toString(), it auto-implements the interface behind scenes and there's definitely no need to manually implement it.

<?php

class Foo {
    public function __toString() {
        return 'I am a class';
    }
}

$obj = new Foo;
dump($obj instanceof Stringable);

Abstract methods in traits improvements (RFC)

Traits support the use of abstract methods in order to impose requirements upon the exhibiting class.

trait Test {
    abstract public function test(int $input): int;
}

class UsesTrait
{
    use Test;

    public function test($input)
    {
        return $input;
    }
}

Throw expression (RFC)

The throw statement can now be used to be utilized in spots where just expressions are permitted, similar to arrow functions, the coalesce operator, and the ternary/elvis operator.

$triggerError = fn () => throw new MyError();

$foo = $bar['offset'] ?? throw new OffsetDoesNotExist('offset');

Trailing Comma in Parameter List (RFC)

PHP 8 permits an optional trailing comma in the parameter list. This includes parameter lists for functions, methods, and closures.

public function(
    string $parameterA,
    int $parameterB,
    Foo $objectfoo, // trailing comma
) {
    // …
}

Catching exceptions without storing in a variable (RFC)

Before PHP 8, it required that captured the exception should be stored Variable, whether or not you utilized that variable or not.

// Before PHP 8
try {
    // Something goes wrong
} catch (MySpecialException $exception) {
    Log::error("Something went wrong");
}

You can now do this:

try {
    // Something goes wrong
} catch (MySpecialException) {
    Log::error("Something went wrong");
}

Attributes

Attributes are certainly the major change in PHP 8, and they can be somewhat tricky to comprehend from the start. In short, attributes permit you to add meta-data to PHP functions, parameters, classes, and so on. This meta-data would then be able to be retrieved programmatically - while in PHP 7 and lower, you would need to parse doclocks, attributes permit you to access to this data deeply integrated into PHP itself.

For example, let's say that you need to allow users to add a middleware to a controller class/method by utilizing an attribute.

<?php
// First, we need to define the attribute. An Attribute itself is just a plain PHP class, that is annotated as an Attribute itself.

#[Attribute]
class ApplyMiddleware
{
    public array $middlware = [];

    public function __construct(...$middleware) {
        $this->middleware = $middleware;
    }
}

// This adds the attribute to the MyController class, with the "auth" middleware as an argument.

#[ApplyMiddleware('auth')]
class MyController
{
    public function index() {}
}

// We can then retrieve all ApplyMiddleware attributes on our class using reflection
// And read the given middleware arguments.

$reflectionClass = new ReflectionClass(MyController::class);

$attributes = $reflectionClass->getAttributes(ApplyMiddleware::class);

foreach ($attributes as $attribute) {
    $middlewareAttribute = $attribute->newInstance();
    dump($middlewareAttribute->middleware);
}

exit;

PHP 8's attributes actually consist of a number of RFCs:

  1. RFC: https://wiki.php.net/rfc/attributes_v2

  2. RFC: https://wiki.php.net/rfc/attribute_amendments

  3. RFC: https://wiki.php.net/rfc/shorter_attribute_syntax

  4. RFC: https://wiki.php.net/rfc/shorter_attribute_syntax_change

Constructor Property promotion (RFC)

This RFC proposes to introduce a shorthand syntax, which permits combining the definition of properties and the constructor.

In PHP 7.x

class Money 
{
    public Currency $currency;
 
    public int $amount;
 
    public function __construct(
        Currency $currency,
        int $amount,
    ) {
        $this->currency = $currency;
        $this->amount = $amount;
    }
}

Now in PHP 8:

class Money 
{
    public function __construct(
        public Currency $currency,
        public int $amount,
    ) {}
}

Match Expression (RFC)

The match expression presented in PHP 8 is like the switch statement. The match can return values, doesn't need lengthy statements like a switch. It utilizes a strict type of comparison and doesn't do any sort of coercion.

<?php

echo match (1) {
    0 => 'Foo',
    1 => 'Bar',
    2 => 'Baz',
};

Null Safe Operator (RFC)

Greatly improve the readability of the code, Instead of writing a few 'If statements' you can utilize the ?-> operator to write all those in just 1 line of code.

<?php

class User {
	public function getAddress() {}
}

$user = new User();

$country = $user?->getAddress()?->country?->iso_code;

dump($country);

Named Arguments (RFC)

Named arguments allow passing arguments to a function based on the parameter name, rather than the parameter position. This makes the meaning of the argument self-documenting, makes the arguments order-independent, and allows skipping default values arbitrarily.

<?php

// Using positional arguments:
array_fill(0, 100, 50);
 
// Using named arguments:
array_fill(start_index: 0, num: 100, value: 50);

JIT Compiler (RFC)

The most interesting feature coming with PHP 8 is the Just-in-time (JIT) compiler.

PHP JIT is implemented as an almost independent part of OPcache. It may be enabled/disabled at PHP compile time and at run-time. When enabled, native code of PHP files is stored in an additional region of the OPcache shared memory and op_array->opcodes[].handler(s) keep pointers to the entry points of JIT-ed code. This approach doesn't require engine modification at all.

New PHP Functions

`str_contains()` function - RFC

str_contains checks if a string is contained in another string and returns a boolean value (true/false) whether or not the string was found.

Now, don't have to depend on strpos() any longer to know whether a string contains another string.

Instead of doing this:

if (strpos('string with lots of words', 'words') !== false) 
{ 
    /* … */ 
}

You can now do this

if (str_contains('string with lots of words', 'words')) 
{ 
    /* … */ 
}

`str_starts_with()` and `str_ends_with()` functions - RFC

str_starts_with() checks if a string begins with another string and returns a boolean value (true/false) whether it does.

str_starts_with('haystack', 'hay'); // true

str_ends_with() checks if a string ends with another string and returns a boolean value (true/false) whether it does.

str_ends_with('haystack', 'stack'); // true

`get_debug_type()` function - RFC

This RFC proposes to add a new function get_debug_type that will return the given type of a variable.

class Book {}

class Comments {}

$book = new Book();

// earlier 
if(! ($book instanceof Comment)) {
  echo 'Expected ' .  Comment::class . ' but got the ' .  (is_object($book) ? get_class($book) : gettype($book));
}

//in PHP8
if(! ($book instanceof Comment)) {
  echo 'Expected ' .  Comment::class . ' but got the ' .  get_debug_type($book);;
}

Conclusions

A lot of work has gone into the release of PHP 8. And the PHP 8 is a sure step towards cleaning up the language and a delivery that brings some long-awaited features.

For a full list of changes or to get some context on why something was introduced, be sure to look at the implemented RFCs for PHP 8

0

Please login or create new account to add your comment.

0 comments
You may also like:

How to Upload Multiple Images with jQuery AJAX and PHP, with preview

Uploading an image without page refresh is more user-friendly than refreshing the entire page. So, in this guide, you will learn how to upload multiple images using ajax in jQuery (...)
Nakul Kumar

How to Add Google reCAPTCHA to a PHP Form with Example?

In this guide, we will integrate the Google reCAPTCHA in the PHP contact form. Utilizing this Google reCAPTCHA code, we can validate the human users and protect the form of submission (...)
Nakul Kumar

How To Install LEMP stack (Linux, Nginx, MySQL, PHP) on Ubuntu System

The term LEMP is an acronym of the four open-source projects:
Harish Kumar

How to connect a PostgreSQL database server using PHP PDO?

Before connecting with the PostgreSQL database using PHP PDO, make sure PHP PDO PostgreSQL driver enabled.
Razet

How to create PHP Pagination using PDO with example?

In this example, I am going to show you how to create pagination in PHP using PDO.First, create a DatabaseConnection.php to create a database connection.
Razet

PHP PDO tutorial with CRUD operation example

One of the most significant PHP extension is called PHP Data Objects or PDO, which was available since PHP 5.0. PDO gives an interface to working with different RDBMS, including (...)
Razet