Php 8 is coming

The PHP development process

Since PHP's release in 1997, the language has evolved considerably. It began as a simple wrapper around C so that Rasmus Lerdorf could build Web sites faster, but the syntax of version 7.4 bears little resemblance to this first PHP release.

The reputation for PHP not being a serious development language is long gone. Almost 80 percent of all websites built on the server side are written in PHP. The Netherlands' nicest tech site is also "powered by" PHP.

A new major version, PHP 8, will be released in December. The first test version of PHP 8 has been available for three months and the first release candidate is scheduled for Sept. 17. With a feature freeze over a month behind us, this is a great time to see what changes PHP 8 brings.

RFC process

To understand how this new version of PHP came about, it is important to look at the development process. It starts with the guardians of PHP, the core developers. These are the developers with the most experience working in PHP source code, and they handle bug reports. They have the additional task of steering PHP development in the right direction. Not only is PHP's source code open, but so is its development path. Anyone who has accumulated a little karma is free to submit a Request For Comments to improve the language.

Whether an RFC succeeds depends on whether the author was able to convince the core developers of its usefulness. The core developers look not only at the proposal itself, but also at the impact on the rest of the language, whether it is consistent with PHP's vision and the extent to which backwards compatibility has been taken into account.

For starters, it is wise to do research and poll the change among core developers, so as not to expend unnecessary energy on a proposal that is unlikely to make it anyway. A proposal to equalize job titles and order of arguments is unlikely to be accepted because the implications would be too great.

When a proposal has enough support, it can be published by a member on the wiki, and announced on the PHP mailing list. This will be followed by a discussion phase, where everyone can ask questions and raise anticipated issues about the RFC. These questions and issues are all recorded in the RFC. When the discussion is complete, but no sooner than two weeks after publication of the RFC, a vote will follow. The vote is always a yes/no vote requiring a two-thirds majority for RFC to pass. Sometimes, in addition to a yes/no vote, there are one or more follow-up votes, which may be about the implementation approach. Voting is reserved for developers who have contributed to PHP's source code, delegates from the PHP community and regular participants in the internal discussions.

Speed gain

The upgrade from PHP 5 to 7 allowed many websites to be rendered much faster, without having to modify the PHP code. This was due to the update of the virtual machine that eventually executes the php code, the zend engine, from version 2 to 3.

Dmitry Stogov, the developer who had taken on the task of making PHP faster, initially wanted speed gains from JIT. He hoped to be able to execute PHP code faster by converting it to machine code just before execution, just as in Java, for example.

However, he found that memory management and internal functions were bottlenecks to execution time. So he decided to improve it first, hoping that PHP code could be executed faster. Indeed, after a few months of work, it turned out that a considerable speed gain had been achieved, and this proof of concept named phpng stood at the cradle of zend engine version 3.

PHP 8 does now introduce JIT. JIT, or just in time, is a way to compile a script before executing it. This is the counterpart of AOT, or ahead of time, where you compile a program in advance, as is the case in C and C++, for example.

The proposal to include JIT in PHP 8 was passed overwhelmingly last March

To understand the benefit of this, it is important to understand how PHP is implemented. A PHP script is first converted by a lexer to tokens, which are then converted by a parser to an abstract syntax tree, or AST. The AST is then compiled into opcodes that are executed by the virtual machine. In PHP 7, the opcache extension can store the compiled version in memory so that lexing, parsing and compiling do not have to be done over and over again and the opcodes are executed directly in the virtual machine. This allows frequently used scripts to run faster.

JIT goes one step further and does not store the opcached version of a script, but compiles the opcode to machine code, such as x86 instructions. This then executes the code not in the virtual machine, but directly on the processor. In theory, this allows scripts to gain even more speed. The caveat here is that this mainly benefits code bound to the cpu. However, many PHP applications will be mostly io bound because they are waiting for a database, for example. So the question is to what extent JIT can provide speed gains for Web sites written in PHP. Therefore, it seems that JIT may be especially interesting for creating other types of applications in PHP. Also, it could be an alternative to convert some extensions currently written in C to PHP code.

Changes under the hood

Expand negative key values

It is possible in PHP to expand an array with a new element, "counting through" the key value using the highest key value. This count-through works only if the key value is 0 or greater. If there is no key value of 0 or greater, then counting through starts at 0.

<?php
$d[-2] = true;
$d[] = true;
$d[] = true;

In PHP 7.4 and below, this returns an array with the key values -2, 0 and 1. PHP 8 dropped the restriction that a key value must be 0 or greater. This means that in PHP 8 the key values are -2, -1 and 0.

More changes

PHP has made more frequent changes in recent releases that allow developers to use the language more rigorously. Version 7's declare(strict_types) is a recent example of this. The standard PHP library, or SPL, also seems to be getting stricter, or at least more consistent, by giving an error more often starting in PHP 8. Nikita Popov, one of the core developers, submitted an RFC for this and also built it himself. As a result, more functions that receive an argument of the wrong type will not give a warning, but will give a TypeError, as is now done in userland functions with type hinting.

Another technical change in PHP 8 is so-called stable sorting. Before PHP 8, the position of elements with the same value in an array after sorting was not guaranteed. So it may mean that those elements are in a different order after sorting. PHP 8 guarantees that elements are in the same order as before sorting, when elements are equal to each other. This seems like a small difference, but can cause subtle bugs with certain code. These will then likely come to light during the upgrade to PHP 8.

Syntax changes

PHP 8 has accepted some RFCs that mainly make reading and typing code easier, without affecting script execution.

Improved argument definition in functions and closures

It will be possible in PHP 8 to have a list of arguments end with a comma in a function definition and in closures, without a new argument following it. This was already possible within an array definition, and when calling functions, but now that this is also possible with function definitions, the language becomes more consistent. The advantage of allowing such a comma is that diff patches are simpler, and it makes adding new values easier.

Constructor property promotion

Another change in PHP 8 is the ability to more easily create a value object thanks to constructor property promotion. This allows a developer to define the type with visibility, assignment and any default value of a property in one place in a class, instead of having to do it in three places. The RFC for this change has the following example of code in PHP 7.4:

<?php
class Point {
	public float $x;
	public float $y;
	public float $z;
 
	public function __construct(
  float $x = 0.0,
  float $y = 0.0,
  float $z = 0.0
  ) {
  $this->x = $x;
  $this->y = $y;
  $this->z = $z;
  }
}

With constructor property promotion, this code can be written in PHP 8 as follows:

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

Code needs to be typed less often, reducing the chances of errors in code creation and refactoring.

Featured new features

In addition to optimizations and syntax tweaks, PHP 8 again has a number of new features that can make developers' work easier. Here is an overview of some accepted RFCs.

Attributes

For many followers of PHP 8 developments, attributes are the feature most anticipated. This is also reflected in the number of RFCs, as a large proportion of RFCs refer directly or indirectly to attributes.

The first attempt to add attributes to PHP dates back to 2016; this RFC did not gain enough votes at the time. With PHP 8, attributes become a part of the language. The new RFC is different in content from the initial proposal for attributes, but the main reason it has now been accepted is probably that the language is now "ripe" for this addition.

The concept of attributes is better known in Java as annotations and in Python as decorators. It is a way of assigning metadata to a class, interface, property, (anonymous) function, method, class constant or capacity. This metadata can then be read with the reflection extension.

Despite the fact that PHP had no official support for attributes, several applications and frameworks came up with alternatives. A common alternative is the use of annotations in doc-comments, where a line in the doc-comment begins with a monkey tail followed by a keyword that has special meaning. The disadvantage of using doc-comments is that the application or framework itself must parse the content of a doc-comment. By making attributes part of PHP's syntax, these attributes can simply be read with Tokenizer, a standard part of PHP.

An attribute is resolved and instantiated as a class, which itself must have an attribute to indicate that it is appropriate as an attribute. An attribute can optionally take arguments, which are passed in the constructor of this class. The RFC leaves free what exactly an attribute does. For example, an attribute can be used by a framework to mark methods in a class as routes, or by an ORM to provide variables with the necessary metadata for the storage type.

<?php
// PHP 7
class Product
{
	/**
  * @ORMId
  * @ORMColumn(type="integer")
  * @ORMGeneratedValue
  */
	protected $id;
}
 
// PHP 8
class Product
{
	#[ORM\Id]
#[ORM\Column(type= integer=""]
#[ORM\GeneratedValue]
protected $id;
}

The RFC notes that the use of attributes additionally paves the way for PHP to start using these attributes itself. For example, attributes could be used in the future to help PHP flag functions that are or are not JIT-enabled.

The RFC won an easy victory, but a few more RFCs followed on implementation. In the first accepted version, there was talk of getting << and >> to use as separators for attributes, but a heated debate quickly ensued as to whether this would be readable, easy to write and not confusing to the already existing bitwise operations. This was followed by an RFC to use @@ and, at the last minute, an RFC to still use "#[" as the start tag and "]" as the end tag. Other "details," such as the attribute that marks an attribute itself and whether an attribute is considered a single token or set of tokens, have also been discussed in subsequent RFCs.

Union types

PHP 8 meets with union types developers who want to use type hinting for multiple types. The union type allows a developer to specify multiple type hints for the same parameter, without creating an Interface specifically to do so. In addition to specifying multiple classes, scalars can also be used in union types.

There is also a special type of false that can be declared in a union type. In PHP, there are a number of functions that return a value, or in the case that something has gone wrong: false. Userland functions can indicate the same with this pseudo type. This is semantically more correct than bool as the return type, because it implies that true could also be returned.

<?php
class SimpleCache {
	private array $storage;
 
	public function setData(string $key, string|int|float $data): void {
  $this->storage[$key] = $data;
  }
	public function getData(string $key): string|int|float|false {
  if ( ! array_key_exists($key, $this->storage)) {
  return false;
  }
 
  return $this->storage[$key];
  }
}

Non-capturing catches

In 2013, an RFC had been filed for an anonymous try-catch construction. That RFC was then killed before the ballot, but a new RFC with an almost identical proposal was overwhelmingly accepted for PHP 8. Thanks to this RFC, in PHP 8 it is possible to write a try-catch construct without assigning the exception to a variable. The example from the RFC:

<?php
try {
  changeImportantData();
} catch (PermissionException $ex) {
  echo "You don't have permission to do this";
}

The exception is assigned to the $ex variable, but not used. This may be intentional, but perhaps the developer forgot to do something with the exception. In PHP 8, it is possible to write this as follows:

<?php
try {
  changeImportantData();
} catch (PermissionException) {
  echo "You don't have permission to do this";
}

This makes it clear to the reader that the developer only wants to capture the exception, but not use it otherwise.

Named arguments

With named arguments in PHP 8, it is possible to specify which parameter belongs to each argument. This allows optional arguments to be skipped, and can increase readability when there are multiple arguments.

In the following example, a developer wants to pass only the parameters string and double_encode to htmlspecialchars, but because double_encode is the fourth parameter, the developer must also specify parameters 2 and 3 with the appropriate default values. Also, it is not clear which parameter false belongs to. In PHP 8, the other parameters can be skipped, and it is also immediately clear that false is the argument to double_encode:

<?php
// PHP 7
htmlspecialchars($string, ENT_COMPAT|ENT_HTML401, ini_get('default_charset'), false));
 
// PHP 8
htmlspecialchars($string, double_encode:false);

Match expression

PHP 8 introduces the match expression : a variant of the switch statement that does a strict comparison, has no fallthrough and can be assigned directly to a variable.

<?php
$winner = match(1337) {
  1336 => 'Adriaan'
  1337 => 'Henk',
  1338 => 'Bassie',
};

Nullsafe operator

The nullsafe operator makes it easier to chain methods without having to explicitly test for null. The nullsafe operator interrupts the chain as soon as a null value occurs in the chain.

<?php
// PHP 7
$theAnswer = null;
 
if ($earth !== null) {
  $human = $earth->extractHuman('Arthur Dent');
 
  if ($human !== null) {
  $brain = $human->getBrain();
 
  if ($brain !== null) {
  $theAnswer = $brain->getAnswer();
  }
  }
}
 
// PHP 8
$theAnswer = $earth?->extractHuman('Arthur Dent')?->getBrain()?->getAnswer();

Standard PHP Library customizations

Outside the engine, PHP also has an extensive collection of internal functions: Standard PHP Library, or SPL.

Philipp Tanlak, a PHP user, has submitted his first RFC for str_contains, a function that looks to see if a substring appears in a string. PHP has had the strpos function since version 4, which specifies the position of a substring in a string and starts at 0. A problem occurs, according to the RFC, when the result of this function is compared to a boolean. The problem arises because an integer 0 is cast to boolean false if the substring in the string occurs at the first position.

The newly proposed function str_contains will always return a boolean, making this safer to use when compared to a boolean true or false.

Will Hudgins, also an unknown in the world of RFCs, has suggested also introducing str_starts_with and str_ends_with functions, which, like str_contains, return a boolean. This RFC has also been accepted and therefore these three functions will be available in PHP 8.

Deprecations

Despite RFCs being reviewed for backwards compatibility, among other things, PHP 8 is a new major version and thus will remove things that are no longer supported.

PHP has a convention of marking things that are removed as deprecated first, before they are removed in a major version. So if developers have been keeping a close eye on their logs, and not skipping a minor version when upgrading, these depreciations will not be unexpected.

In conclusion

To keep abreast of all PHP's changes, you can start reading the RFCs, subscribe to PHP's newsgroup or look up a PHP user group near you.

For a complete overview, check out PHP 8 's release notes, and come prepared when you upgrade. What PHP 8.1 will bring us is not yet clear, but the first RFCs have already been written.

(source : https://tweakers.net/reviews/8168/all/php-8-is-op-komst-jit-stable-sorting-en-meer-vernieuwingen.html )