DEV Community

Cover image for What's new in PHP 8
Sesha
Sesha

Posted on • Updated on

What's new in PHP 8

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

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();
}


Enter fullscreen mode Exit fullscreen mode

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

// 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());
Enter fullscreen mode Exit fullscreen mode

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

//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
Enter fullscreen mode Exit fullscreen mode

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

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

Enter fullscreen mode Exit fullscreen mode

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

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

Enter fullscreen mode Exit fullscreen mode

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

Here how they will work,

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',
);

Enter fullscreen mode Exit fullscreen mode

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

 str_contains ( string $haystack , string $needle ) : bool
Enter fullscreen mode Exit fullscreen mode

It checks the needle found in the haystack and returns the boolean.

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';
 }

Enter fullscreen mode Exit fullscreen mode

str_start_with

It checks the given haystack starts with the needle.

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'";
}
Enter fullscreen mode Exit fullscreen mode

str_ends_with

It checks the given haystack ends with the needle.

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'";
}
Enter fullscreen mode Exit fullscreen mode

get_debug_type

It's pretty straight forward just returns the type of the variable.
Here an example.

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);;
}
Enter fullscreen mode Exit fullscreen mode

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

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.

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)
Enter fullscreen mode Exit fullscreen mode

Throw Expression

This RFC 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.

$callable = fn() => throw new Exception();

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

// $value is truthy.
$value = $falsableValue ?: throw new InvalidArgumentException();
Enter fullscreen mode Exit fullscreen mode

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..
Here a simple example.

class Comment {
  public function __construct(
   string $titla,
   string $description,
   int $status, // trailing comma
 ) {
   // do something
 }
}
Enter fullscreen mode Exit fullscreen mode

Incompatible Method Signatures

Now, this RFC proposes to always throw a fatal error for incompatible method signatures.

Consider the a following simple example:

class Product {
 public function get(string $price) {}
}
class SubProduct extends Product {
 public function get(int $price) {}
}
Enter fullscreen mode Exit fullscreen mode

In PHP 7.4, the code above would simply throw a warning:

Warning: Declaration of SubProduct::get(int $price) should be compatible with Product::get(string $price) in /path/to/your/index.php on line 7
Enter fullscreen mode Exit fullscreen mode

With PHP 8, It throws a fatal error

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
Enter fullscreen mode Exit fullscreen mode

Arrays Starting With a Negative Index

Now, this RFC proposes the second index would be start_index + 1

Consider the following example.

$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
Enter fullscreen mode Exit fullscreen mode

Validation for Abstract Trait Methods

Now this RFC proposes to throw a fatal error if the implementing method is not compatible with the abstract trait method.

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

Enter fullscreen mode Exit fullscreen mode

Mixed Type

Mixed type is a good addition to php8 type system. It is equivalent to one of these types.

  array|bool|callable|int|float|null|object|resource|string
Enter fullscreen mode Exit fullscreen mode

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.
// 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) {}
}
Enter fullscreen mode Exit fullscreen mode
  • A parameter type may not be narrowed in a subclass to a more specific type as this is not contravariant and so violates LSP.
// 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) {}
}
Enter fullscreen mode Exit fullscreen mode

Return types are covariant

// 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  {}
}
Enter fullscreen mode Exit fullscreen mode

Property types are invariant

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;
}
Enter fullscreen mode Exit fullscreen mode

And finally, one more thing to remember:
// Fatal error: Mixed types cannot be nullable, null is already part of the mixed type.

function book(): ?mixed {} 
Enter fullscreen mode Exit fullscreen mode

You can read more from the RFC

Non-Capturing Catches

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

//Before PHP 8
try {
    AddUser();
} catch (PermissionException $ex) {
    echo "You don't have permission to add user";
}
Enter fullscreen mode Exit fullscreen mode

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 8
try {
    AddUser();
} catch (PermissionException) {   //The intention is clear: exception details are irrelevant
    echo "You don't have permission to add user";
}
Enter fullscreen mode Exit fullscreen mode

Inheritance with private methods

This RFC 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.

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
Enter fullscreen mode Exit fullscreen mode

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 ...
Enter fullscreen mode Exit fullscreen mode

JIT Compiler (Just in Time Compiler)

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

The RFC proposal 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 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

Top comments (4)

Collapse
 
mdhesari profile image
Mohammad Fazel

Good work! Thank you.

Collapse
 
sesha profile image
Sesha

Thank you, sir.

Collapse
 
arturssmirnovs profile image
Arturs Smirnovs

Thanks for article..

Collapse
 
sesha profile image
Sesha

Thank you, sir!