What's new in PHP 8.0

 A few stats

$ git diff --shortstat e1181511 HEAD
17258 files changed, 665695 insertions(+), 781953 deletions(-)

$ git rev-list --count --no-merges PHP-7.4..PHP-8.0
3791

$ git shortlog --summary --oneline --no-merges PHP-7.4..PHP-8.0|sort -r
  1334  Nikita Popov
   651  Dmitry Stogov
   357  Máté Kocsis
   312  George Peter Banyard
   303  Christoph M. Becker
    81  Tyson Andre
    78  Remi Collet
    56  Alex Dowad
    48  Gabriel Caruso
    29  Benjamin Eberlei
    27  Xinchen Hui
    21  Stanislav Malyshev

Branched on 2019-01-28

GA release on 2020-11-26

44 accepted RFCs

15 rejected RFCs

Highlighted

new features

JIT

Attributes

class User
{
    #[ORM\Id, ORM\Column("integer"), ORM\GeneratedValue]
    private $id;
 
    #[ORM\Column("string", ORM\Column::UNIQUE)]
    #[Assert\Email(["message" => "The email is not valid"])]
    private $email;
}

Match Expression

$statement = match ($token) {
    Lexer::T_SELECT => $this->SelectStatement(),
    Lexer::T_UPDATE => $this->UpdateStatement(),
    Lexer::T_DELETE => $this->DeleteStatement(),
    default => $this->syntaxError('SELECT, UPDATE or DELETE'),
};

Property Promotion

class Point
{
    public function __construct(
        public float $x = 0.0,
        public float $y = 0.0,
        public float $z = 0.0,
    ) {}
}

Named Parameters

class ParamNode extends Node
{
    public function __construct(
        public string $name,
        public ExprNode $default = null,
        public TypeNode $type = null,
        public bool $byRef = false,
        public bool $variadic = false,
        Location $startLoc = null,
        Location $endLoc = null,
    ) {
        parent::__construct($startLoc, $endLoc);
    }
}

new ParamNode($name, byRef: $passByRef, variadic: $isVariadic);

Nullsafe Operator

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

Type System Improvements

Union Types

class Number
{
    private int|float $number;
 
    public function setNumber(int|float $number): void
    {
        $this->number = $number;
    }
 
    public function getNumber(): int|float
    {
        return $this->number;
    }
}

Static Return Type

class Test
{
    public function createFromWhatever($whatever): static
    {
        return new static($whatever);
    }
}

Mixed Type

function debug_type(mixed $variable)
{
    $type = gettype($variable);

    return match($type) {
        "boolean" => "bool",
        "integer" => "int",
        "double" => "float",
        "resource (closed)",
        "resource" => "resource (".get_resource_type($variable).")",
        "NULL" => "null",
        default => $type,
    };
}

Highlighted

BC breaks

7.x Deprecations

class X
{
    public function X($x)
    {
    }
}

$x = new X();

// Works!

X::X();

// Uncaught Error: Non-static method X::X() cannot be called statically

define("X", 1, true);

// Warning: define(): Argument #3 ($case_insensitive) is ignored since
// declaration of case-insensitive constants is no longer supported

https://github.com/php/php-src/pull/3770 (sans 7.4)

Magic Method Signatures

class Foo
{
    public function __toString(): bool
    {
        return true;
    }
}

// Works on PHP 7.4

// PHP 8.0:
// Fatal error: Declaration of Foo::__toString(): bool must be
// compatible with Stringable::__toString(): string

Fatal on Incompatible Signatures

class C1
{
    public function method(array $a) {}
}

class C2 extends C1
{
    public function method(int $a) {}
}

// PHP 7.4:
// Warning: Declaration of C2::method(int $a) should be compatible
// with C1::method(array $a)

// PHP 8.0:
// Fatal error: Declaration of C2::method(int $a) must be compatible
// with C1::method(array $a)

Consistent Type Errors

var_dump(strlen(new stdClass));

// PHP 7.4:
// Warning: strlen() expects parameter 1 to be string, object given
NULL

// PHP 8.0:
// Uncaught TypeError: strlen(): Argument #1 ($str) must be of type
// string, stdClass given

Reclassify Engine Errors

var_dump($x);    // Warning: Undefined variable $x

$x = [];
var_dump($x[0]); // Warning: Undefined array key 0

12 / 0;          // DivisionByZeroError: Division by zero

(string) [];     // Warning: Array to string conversion

700+ warnings were reclassified to an exception

Numeric String Changes

function foo(int $i) { var_dump($i); }

foo("   123"); // int(123)
foo("123   "); // int(123)
foo("123abc"); // TypeError

var_dump(123 + "   123"); // int(246)
var_dump(123 + "123   "); // int(246)
var_dump(123 + "123abc"); // int(246) with E_WARNING
var_dump(123 + "string"); // TypeError

                         // Before | After | Type
var_dump(42 == "   42"); // true   | true  | well-formed
var_dump(42 == "42   "); // true   | false | non well-forme
var_dump(42 == "42abc"); // true   | false | non well-formed
var_dump(42 == "abc42"); // false  | false | non-numeric
var_dump( 0 == "abc42"); // true   | false | non-numeric

Float to String Cast

setlocale(LC_ALL, "hu_HU");
$f = 3.14;
 
var_dump($f);

// PHP 7.4:
// float (3,14)

// PHP 8.0
// float (3.14)


// PHP 7.4 + OPCache:
var_dump(3.14 . "");

// string(4) "3.14"

Arithmetic/Bitwise Operators

$result = [] % [42];   // TypeError: Unsupported operand types

$array = [2, 3];
$array++;              // TypeError: Cannot increment array

$object = new stdClass();
$object++;             // TypeError: Cannot increment stdClass

What's new in PHP 8.0

By Máté Kocsis

What's new in PHP 8.0

  • 454