The State of PHP 8

Leia em Português

Important update! PHP 8.0 was already released. You can check out this great summary containing the main news on this version.

PHP 8.0 is currently being discussed and developed. This means that many things in this post will still change a lot over time. For each field of interest I'll leave a subheading and as discussions move further inside php community they'll be properly updated.

It should be clear that I won't be able to post every single update in real time as there are many things happening every day. If you're looking for a fresh up-to-date list, please refer to the UPGRADING file in the official repo.

When will PHP 8.0 be released?

PHP 8.0 will be released on December 2020. At least this is where the official schedule is pointing to.

PHP 7.4 got released not long ago and there won't be another minor version (PHP 7.5) for this major 7. So the next version will definitely be PHP 8.


Accepted features for PHP 8.0

Features listed below will be delivered within PHP 8.0's release. They were already voted, accepted AND implemented.

So if you want to have a taste of this version, check this section out:

JIT: Just in Time Compiler

I wrote an in-depth explanation about what the heck the Just In Time compiler is.

This feature claims to be more than four times faster on Mandelbrot benchmark and should cause big impacts on CPU-bound operations.

You can check the full spec by visiting the RFC page.

Union Types V2

The Union Types V2 RFC will allow every type definition to explicitly tell what possibilities are accepted, instead of trusting the good old mixed.

New syntax will look like the following:

function myFunction(int|float $number): int
{
  return round($number);
}

The WeakMap class

The WeakMap class RFC creates a new class called WeakMap which looks a bit like SplObjectStorage.

The main idea is that you can create a object -> value map in it, without preventing this object from being garbage collected. Thus the Weak name, stating there's a weak reference between the key object and the map itself.

Garbage collecting an object used as key in such map will cause its removal, meaning the value will be removed. Like the following:

$map = new WeakMap();
$obj = new DateTime('today');

$map[$obj] = 100;

// Shows one key
var_dump($map);

// Remove $obj from memory
unset($obj);

// WeakMap is now empty
var_dump($map);

Edit (2020.01.20): if you want to give it a try, there's already a polyfill implementation that works with PHP 7.4; It is called BenMorel/weakmap-polyfill.

TypeError exceptions will be thrown on parameter parsing failures

Whenever you cause a type error on user-defined functions, it will throw an exception. For internal functions, though, PHP shows a warning and returns null by default.

The consistent TypeError RFC makes both behaviours consistent, by throwing TypeError exceptions in both cases.

Implicit array keys will be more consistent

Whenever you use negative indexes on the array_fill function, it will generate the first negative index and then jump to 0 (🤦‍♀️). Like this:

$a = array_fill(-2, 3, true);
var_dump($a);

// outputs
array(3) {
  [-2] =>
  bool(true)
  [0] =>
  bool(true)
  [1] =>
  bool(true)
}

So the Negative Array Index RFC aims to fix this behaviour by letting array_fill properly step with negative indexes:

$a = array_fill(-2, 3, true);
var_dump($a);

// outputs
array(3) {
  [-2] =>
  bool(true)
  [-1] =>
  bool(true)
  [0] =>
    bool(true)
  }

Fatal Error on wrongly typed inherited methods

Whenever a class defines a method signature and its children attempt to overload such method (by changing its signature) a warning is thrown.

This RFC from Nikita Popov makes this behaviour to throw a Fatal Error whenever this overload is attempted.

Here's an example of buggy code on PHP 8:

class A
{
  function x(int $a): int
  {
    // ...
  }
}

class B extends A
{
  // Notice the signature
  // changed. Fatal Error here.
  function x(float $a): float
  {
    // ...
  }
}

DOM API upgrade to match latest standard version

This RFC also requires a post by itself.

But basically it adds a couple of interfaces and classes to make ext/dom API to match the current DOM standard which is constantly changing.


What MIGHT enter PHP 8.0 version?

There are a couple of RFCs still under discussion. They might be denied or accepted any time soon. There are many things related to the core of the language and its syntax.

Here goes the list:

Severity levels for errors messages fixed

The severity error messages' levels RFC aims to make a revision on many core error handling features.

For example the widely known Invalid argument supplied for foreach() might jump from Warning to TypeError Exception.

Allow ::class access on objects

Basically Dynamic class names aren't allowed in compile time. So a code like the following raises a fatal error:

$a = new DateTime();
var_dump($a::class);
// PHP Fatal error:  Dynamic
// class names are not allowed
// in compile-time
// ::class fetch in...

With this RFC it will be now possible.

Make static a valid return type, like self

Just the way we can make self a return type for functions, the static return RFC aims to make static also an available return type.

This way functions like the following would be then correct:

class A
{
  public function b(): static
  {
    return new static();
  }
}

Consistent variables syntax

This one is also about syntax and will change a couple of features.

I recommend you checking out the RFC for more details. Affected language features include:

Optimize function/constants lookup

The RFC about function and constants lookup adds a new declare() statement that prevents PHP from performing lookups on runtime.

Whenever you're in a namespaced code and tries to fetch a globally scoped function or constant without prefixing it with a backslash (\), PHP will first try to find it on the current namespace and then bubble up to the global namespace.

By adding a disable_ambiguous_element_lookup=1 directive, PHP will directly go to the global namespace. Here's an example (from the RFC):

namespace MyNS;
declare(
    strict_types=1,
    disable_ambiguous_element_lookup=1
);
use function OtherNS\my_function;
use const OtherNS\OTHER_CONST;

if (
  // function lookup!!
  version_compare(
    // constant lookup!!
    PHP_VERSION,
    '8.0.5'
  ) >= 0
) {
    // ...
}

disable_ambiguous_element_lookup was zero on the above example, PHP would attempt to find MyNS\PHP_VERSION and MyNS\version_compare first, understand they don't exist (hopefully) and only then attempt the \PHP_VERSION and \version_compare.

When disable_ambiguous_element_lookup equals one, this extra lookup is no longer necessary and PHP will go directly to the global scope, fetching \PHP_VERSION and \version_compare.

Strict Operators directive

The strict operators RFC would add a new directive called strict_operators. When switched on a couple of comparisons would then behave differently.

Here are some examples on how php would behave (from the RFC):

10 > 42;        // false
3.14 < 42;      // true

"foo" > "bar";  // TypeError("Unsupported type string for comparison")
"foo" > 10;     // TypeError("Operator type mismatch string and int for comparison")

"foo" == "bar"; // false
"foo" == 10;    // TypeError("Operator type mismatch string and int for comparison")
"foo" == null;  // TypeError("Operator type mismatch string and null for comparison")

true > false;   // true
true != 0;      // TypeError("Operator type mismatch bool and int for comparison")

[10] > [];      // TypeError("Unsupported type array for comparison")
[10] == [];     // false

"120" > "99.9";               // TypeError("Unsupported type string for comparison")
(float)"120" > (float)"99.9"; // true

"100" == "1e1";               // false
(int)"100" == (int)"1e2";     // true

"120" <=> "99.9";             // TypeError("Unsupported type string for comparison")

Changes are much wider than this example and are out of the scope of this single post. Check the RFC for more, or ping me on twitter if you'd like to see a blog post about this one! 😉


The RFCs below are still under discussion and most of them have something related to past versions of PHP, not being able to get released in time or something similar. I won't describe them in detail just yet, as I don't quite feel they have big changes to be integrated to the language.

I will, of course, follow up on them to make sure I'm hopefully wrong.

Here they are:

Auto Increment value on copy on write

RFC link.

This RFC was originally targeting PHP 7.4 but is still marked as Under Discussion. So I'd expect it to retarget PHP 8.0 this time.

Alternative "use" syntax on Closures

RFC link.

This RFC was originally targeting "the next minor version", which at that time would be php version 7.4.

Apply a declare() to an entire Namespace 🔥

RFC link.

Permit trailing spaces on numeric strings

RFC link.

This RFC also targeted version 7.4 and didn't make it in time.

Allow nullable type casting

RFC link.

Apparently the fork containing the Work In Progress for such change got deleted. And the Pull Request closed. Doesn't seem like it will ever be integrated unless someone take over this one.


So far, that's it. I'll add some Edit on topics over time, as the community moves forward and I get the opportunity to see statuses changing.

If you found something wrong or would like to add something missing here, feel free to ping me on twitter or open an issue on the public repository.