What's new in PHP 8
Tags: php8, php, laravel, web
Published: 2020-11-15 13:37:30

---
title: What's new in PHP 8
published: true
description: What’s New in PHP 8
tags: php8,PHP,Laravel,Web
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/d65mqttdwwyek6hyw3uv.jpg
---

## Index
1. Null Safe Operator
2. Union Types
3. Match Expression
4. Constructor Property promotion
5. $object::class
6. Named Arguments
7. New PHP Functions
8. Attributes v2
9. Weak Maps
10. Throw Expression
11. Trailing Comma in Parameter List
12. Incompatible Method Signatures
13. Arrays Starting With a Negative Index
14. Validation for Abstract Trait Methods
15. Mixed Type
16. Non-Capturing Catches
17. Inheritance with private methods
18. JIT Complier
19. Breaking Changes and Depreciations


## Nullsafe operator
Greatly improve the readability of the code, Instead of writing several 'If statements' you can use the “?” operator to write all those in just 1 line of code.  [RFC..](https://wiki.php.net/rfc/nullsafe_operator)

```php 
class Book {
  public function comments() {
    return new Comments;  //or return null
  }
}

class Comments {
  public function get() {
    return [ 
      'title' => 'My first comment'
    ];
  }
}

$book  = new Book();

// PHP8.x
$book->comments()?->get();

// php7.x
if($book->comments()) {
  $book->comments()->get();
}


```
## Union Types 2.0

PHP is a dynamically typed structure, So union types are very useful in a lot of places.

Union types are specified using the syntax T1|T2|... and can be used in all positions where types are currently accepted.
[RFC..](https://wiki.php.net/rfc/union_types_v2#php_rfcunion_types_20)


```php 
// 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;
  }
}

//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());
```


## Match Expression
Does match expression replace the switch?. The match can return values, doesn't require lengthy statements like a switch. It uses strict type comparison and doesn't do any type coercion. [RFC..](https://wiki.php.net/rfc/match_expression_v2)

```php
//The switch statement loosely compares (==) the given value to the case values. This can lead to some very surprising results.
switch ('100') {
  case 100:
    $price = "Oh no!";
    break;
  case '100':
    $price = "This is what I expected";
    break;
}
echo $price;
///> Oh no!

//The match expression uses strict comparison (===) instead. The comparison is strict regardless of strict_types.
echo match ('100') {
  100 => "Oh no!",
  '100' => "This is what I expected",
};
//> This is what I expected
```

## Constructor Property promotion
Why do we need to write a lot of boilerplate?  This constructor property promotion helps to promote properties that are shorter, more readable, and less prone to errors. Consider the following simple example to understand more. [RFC ..](https://wiki.php.net/rfc/constructor_promotion)

```php
// in PHP 7.x
class Product {
  protected $price;
  public function __construct($price) {
    $this->price = $price;
  }
}

class Customer {
  protected $name;
  public function __construct($name) {
    $this->name = $name;
  }
}

class Order {
  protected $product;
  protected $customer;
  public function __construct($product, $customer){
    $this->product = $product;
    $this->customer = $customer;
  }
}


// You can write like this in PHP8
class Product {
  public function __construct(protected string $price) {
  }
}

class Customer {
  public function __construct(protected string $name){
  }
}

class Order {
  public function __construct(
  protected Product $product,
  protected Customer $customer) {
  }
}

// $product = new Product('IPhone 12');
// $customer  = new Customer('your name');
// $order = new Order($product, $customer);
// var_dump($order);

```
So easy right?


## $object::class Syntax
The $object::class used to fetch the name of the class of a given object. $object::class provides the same result as get class($object). If $object is not an object, it throws a TypeError exception. [RFC..](https://wiki.php.net/rfc/class_name_literal_on_object)

```php
class Product{};

$class = match (Product::class)  {
  'Product' => 'Product class',
  'Other' => 'Other class'
};
echo $class; //> Product class
// If Object is null thrown a typeError
$object = null;
var_dump($object::class); // TypeError

```

## Named Arguments
It was a close call but named arguments also called named parameters, it has both ins and outs but for me, they will allow us to write more cleaner and better code. [RFC...](https://wiki.php.net/rfc/named_params)

Here how they will work,
```php
class Log {

  public function __construct(
      private string $title, 
      private string|null $description, 
      private string $type ) {
     
  }
}

$log = new Log (
  title : 'New Support request',
  description : 'You received a new support ...',
  type: 'support',
);

// even you can write something like these
$log = new Log (
  title : 'New Support request',
  type: 'support',
);

// but without this we need to write something like these
$log = new Log (
  'New Support request',
  '',
  'support',
);

```

## PHP New Functions
Here the list of the new functions,
1.str_contains
2.str_start_with
3.str_ends_with
4.get_debug_type

### Str_contains
```php
 str_contains ( string $haystack , string $needle ) : bool
```
It checks the needle found in the haystack and returns the boolean.

```php
if (str_contains('This is my first blog', 'blog')) {
  echo 'blog has been found';
}

//in PHP 7.x
 if (strpos('This is my first blog post', 'blog') !== false) { 
     echo 'blog is has been found';
 }

```

### str_start_with
It checks the given haystack starts with the needle.
```php
str_starts_with (string $haystack , string $needle) : bool

//example
if (str_starts_with('This is my first blog post', "this")) { 
   echo "it is started with 'this'";
}
```

### str_ends_with
It checks the given haystack ends with the needle.
```php
str_ends_with (string $haystack , string $needle) : bool

//example
if (str_ends_with('This is my first blog post', "post")) { 
   echo "it is ended with 'post'";
}
```

### get_debug_type
It's pretty straight forward just returns the type of the variable.
Here an example.
```php
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);;
}
```

## Attributes v2
Attributes are known as the annotations in many other languages, it's to add metadata to classes, methods, variables, parameters, and constants. without having a parse doc block. [RFC...](https://wiki.php.net/rfc/attributes_v2).

## Weak Maps
 It's used for storing references, It allows us to create a map from objects to arbitrary values without preventing the objects that are used as keys from being garbage collected

In long-running processes, this would prevent memory leaks and improve performance. See the following example from the RFC:

Here is an example.
```php
class Population{
}

class Country {
  protected WeakMap $total;

  public function __construct() {
    $this->total = new WeakMap();
  }
  public function IncrementPopulation(Population $pop) :void {
    $this->total[$pop] ??= 0;
    $this->total[$pop]++;
  }
}

$population = new Population();
$country = new Country();

$country->IncrementPopulation($population);
$country->IncrementPopulation($population);
var_dump($country)
```

## Throw Expression 
[This RFC](https://wiki.php.net/rfc/throw_expression) Change throw from being a statement to being an expression. Earlier we can't able to use this one in some places like arrow functions, the coalesce operator, and the ternary/elvis operator because in these places only expressions are allowed.

Here is an example from RFC.
```php
$callable = fn() => throw new Exception();

// $value is non-nullable.
$value = $nullableValue ?? throw new InvalidArgumentException();
 
// $value is truthy.
$value = $falsableValue ?: throw new InvalidArgumentException();
```

## Trailing Comma in Parameter List
PHP 8 allows an optional trailing comma in the parameter list. This includes parameter lists for functions, methods, and closures. [for more..](https://wiki.php.net/rfc/trailing_comma_in_parameter_list)
Here a simple example.
```php
class Comment {
  public function __construct(
   string $titla,
   string $description,
   int $status, // trailing comma
 ) {
   // do something
 }
}
```
## Incompatible Method Signatures
Now, [this RFC](https://wiki.php.net/rfc/lsp_errors) proposes to always throw a fatal error for incompatible method signatures.

Consider the a following simple example:
```php
class Product {
 public function get(string $price) {}
}
class SubProduct extends Product {
 public function get(int $price) {}
}
```
In PHP 7.4, the code above would simply throw a warning:

```php
Warning: Declaration of SubProduct::get(int $price) should be compatible with Product::get(string $price) in /path/to/your/index.php on line 7
```
With PHP 8, It throws a fatal error
```php
Fatal error:  Declaration of SubProduct::get(int $price) must be compatible with Product::get(string $price) in /path/to/your/index.php on line 7
```

## Arrays Starting With a Negative Index
Now, [this RFC](https://wiki.php.net/rfc/negative_array_index) proposes the second index would be start_index + 1

Consider the following example.
```php
$book = array_fill(-4, 6, 'title');
var_dump($book);
//output 
array(6) {
  [-4]=>
  string(5) "title"
  [-3]=>
  string(5) "title"
  [-2]=>
  string(5) "title"
  [-1]=>
  string(5) "title"
  [0]=>
  string(5) "title"
  [1]=>
  string(5) "title"
}

// In PHP 7.4 like these
//output 
array(6) {
  [-4]=>
  string(5) "title"
  [0]=>
  string(5) "title"
  [1]=>
  string(5) "title"
  [2]=>
  string(5) "title"
  [3]=>
  string(5) "title"
  [4]=>
  string(5) "title"
}
=> null
```

## Validation for Abstract Trait Methods
 Now [this RFC](https://wiki.php.net/rfc/abstract_trait_method_validation) proposes to throw a fatal error if the implementing method is not compatible with the abstract trait method.

```php
trait Sluggable {
  abstract public function slug(string $title);
}
class Page {
  use Sluggable;
  // Allowed, but shouldn't be due to invalid type.
  public function slug(int $x) {}
}

// Output
//Fatal error: Declaration of Page::slug(int $x) must be compatible with Sluggable::slug(string $title) in /php8/index.php on line 9

```

## Mixed Type

Mixed type is a good addition to php8 type system. It is equivalent to one of these types.
 ```php 
  array|bool|callable|int|float|null|object|resource|string
```

#### LSP, Covariance and Contravariance

The below things we need to consider
#### Be careful when using mixed type because Parameter types are contravariant.

* Parameter type was widened from int to mixed, this is allowed in LSP. 
```php
// Valid Example
class Project {
    public function title(string $title) {}
}
 
class Task extends Project {
    // Parameter type was widened from int to mixed, this is allowed
    public function title(mixed $title) {}
}
```

* A parameter type may not be narrowed in a subclass to a more specific type as this is not contravariant and so violates LSP.
```php
// Invalid Example
class Project {
  public function title(mixed $title) {}
}

class Task extends Project {
  // Parameter type cannot be narrowed from mixed to string
  // Fatal error thrown
  public function title(string $title) {}
}
```

#### Return types are covariant
```php 
// Valid Example
class Project {
  public function title(string $title) :mixed { }
}
 
class Task extends Project {
  // return type was narrowed from mixed to string, this is allowed 
  public function title(string $title) :string {}
}

// Invalid Example
class Project {
  public function title(string $title)  :string {}
}

class Task extends Project {
  // the return type cannot be widened from string to mixed
  // Fatal error thrown
  public function title(string $title) :mixed  {}
}
```

#### Property types are invariant
```php
class Project {
  public mixed $title;
  public string $description;
  public $priority;
  public int  $points;
}

class Task extends Project {
  // property type cannot be narrowed from mixed to string
  // Fatal error thrown
  public string $title;

  // property type cannot be widened from string to mixed
  // Fatal error thrown
  public mixed  $description;
   
  // property type cannot be added
  // Fatal error thrown
  public int $priority;

  // property type cannot be removed
  // Fatal error thrown
  public  $points;
}
```
And finally, one more thing to remember: 
 // Fatal error: Mixed types cannot be nullable, null is already part of the mixed type.
```php 
function book(): ?mixed {} 
```
You can read more from the [RFC](https://wiki.php.net/rfc/mixed_type_v2)

## Non-Capturing Catches
Before PHP 8, requires to capture the exception being caught to Variable, regardless of whether you used that variable or not.

```php
//Before PHP 8
try {
    AddUser();
} catch (PermissionException $ex) {
    echo "You don't have permission to add user";
}
```
Above, you need to specify the $ex variable even if it's not used.
In PHP 8, you can do that one easily without using $variable
 
```php
//PHP 8
try {
    AddUser();
} catch (PermissionException) {   //The intention is clear: exception details are irrelevant
    echo "You don't have permission to add user";
}
```

## Inheritance with private methods

[This RFC](https://wiki.php.net/rfc/inheritance_private_methods)  remove inappropriate inheritance signature checks on private methods.
   It doesn't make sense because the private method won't able to access by child classes. So applying the same signature rules for all public, protected, and private methods not good. So in PHP 8, the inheritance checks are not performed on private methods anymore.

```php
class Product { 
    final private function slug() { 
        echo 'final  product slug';
    } 
} 

class Category extends Product { 
    private function slug() { 
        echo  'echo category slug ';
    } 
}
// before PHP 8 produces
// Fatal error: Cannot override final method Product::slug()

// In PHP 8 produce
$product = new Product(); 
$product->slug();  
//output : final  product slug

$category = new Category(); 
$category->slug();   //output : final category slug
```
And also using final on private methods doesn't make sense either so using the final keyword on private methods will trigger a warning.
```
Warning: Private methods cannot be final as they are never overridden by other classes in ...
```


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

The [RFC proposal](https://wiki.php.net/rfc/jit) describes JIT as follows:

“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, the 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.”
I would like to write a separate post about JIT to explain more about  It, So stay tuned for that!

## Breaking Changes and Depreciation
 PHP 8  is a major update and there will be some breaking changes. I'm writing a detailed post about breaking Changes and will be published soon. Please follow me on [Twitter]((https://twitter.com/seshaCS) 
) to know more about that.

## Conclusion
I'm very excited and waiting for PHP 8 release. What an interesting improvement and a new feature in PHP 8,  I hope you enjoyed this article, won't you.

Please, let me know your thoughts in the comment section.
If you like this and interested more about like, please follow me [on Twitter](https://twitter.com/seshaCS)