PHP 8.0 is gaining momentum and adoption is increasing, as evidenced by Composer’s statistics.
Meanwhile, PHP internals have accepted a bunch of changes for PHP 8.1, including a new never type and namespaces in bundled PHP extensions, and some features that will be deprecated.
The PHP 8.1 release managers have been selected, and there are several interesting proposals under discussion, including property accessors, pure intersection types, and final constants.
Read more about this news in the May edition of PHP Annotated. As usual, we’ve carefully selected a collection of articles, tools, videos, and streams for you.
-
PHP 8.1 will have a new type for returned values: never
.
A function or method declared with the never
type indicates that it will never return a value, and it either throws an exception or terminates with a call of type die()
, exit()
, trigger_error()
.
It is an empty bottom type and is a subtype of all other types, and there are similar types in Python, Rust, Kotlin, and TypeScript. This type improves static analysis.
function redirect(string $uri): noreturn {
header('Location: ' . $uri);
exit();
}
function redirectToLoginPage(): noreturn {
redirect('/login');
}
You can find more details on PHP.Watch or listen to the PHP Internals News podcast with Matt Brown and Ondřej Mirtes.
-
In PHP 8.1, an E_DEPRECATED
notice will be thrown when float
is converted into int
and fractional part is lost. Later, in PHP 9.0, this will cause a TypeError
.
function acceptInt(int $i) {
var_dump($i);
}
acceptInt(3.1415);
> int(3) // Deprecation notice
Learn more from the
PHP Internals News podcast #83 with George Peter Banyard.
-
In PHP 8.1 the Serializable
interface will be deprecated. A deprecation notice will be thrown when the class uses only this interface, that is, if the class does not additionally have the new magic methods __serialize()
and __unserialize()
.
-
This marks a small step towards cleaner PHP! New symbols (classes, interfaces, etc.) in extensions will now have to use namespaces.
Here’s an example. The resource
type is de-facto obsolete in PHP, and all existing resources are slowly being migrated to objects. In PHP 8.1 some resources will be replaced with the following namespaced classes:
IMAPConnection -> IMAP\Connection
FTPConnection -> FTP\Connection
LDAP -> LDAP\Connection
LDAPResult -> LDAP\Result
LDAPResultEntry -> LDAP\ResultEntry
PgSql -> PgSql\Connection
PgSqlResult -> PgSql\Result
PgSqlLob -> PgSql\Lob
-
Most of the built-in methods in PHP 8.0 have received parameters and return type declarations. In some cases, however, this could not be done, like for the return values of public non-final methods. The problem is that they can be overridden in user code.
Here is an example to illustrate the problem
class SomeStandardClass
{
public function method(): int {}
}
class UserClass extends SomeStandardClass
{
public function method() {}
}
// Fatal error: Declaration of UserClass::method() must be compatible with SomeStandardClass::method()
There will now be a gradual migration for such cases. In PHP 8.1, all internal methods will also get the missing types. If they are overridden in user code, a Deprecation notice will be thrown.
class MyDateTime extends DateTime
{
public function modify(string $modifier) { return false; }
}
// Deprecated: Declaration of MyDateTime::modify(string $modifier) should be compatible with DateTime::modify(string $modifier): DateTime|false
-
There will be three managers this time around: the experienced Joe Watkins (pthreads, parallel, pcov), and two newcomers, Patrick Allaert (blackfire.io) and Ben Ramsey (ramsey/uuid). Check PHP Internals News podcast #84 with Ben and Patrick.
New proposals for PHP 8.1:
-
Partial function application (partial functions) is when only some arguments are bound on function call, and the others remain as parameters to be passed later.
For example, here is a full function:
function whole($one, $two) {
/* ... */
}
And here’s a partial one based on it:
$partial = whole(?, 2);
In this case, the partial signature will look like this:
function($one) {
/* ... */
}
Why is this needed?
Firstly, you can now get a reference to any function or method and pass it wherever Callable
is expected. For example, you could do this
array_map(Something::toString(?), [1, 2, 3]);
array_map(strval(?), [1, 2, 3]);
// instead of
array_map([Something::class, 'toString'], [1, 2, 3])
array_map('strval', [1, 2, 3]);
And secondly, as a consequence, it will be possible to implement the pipe operator |>
:
$result = "Hello World"
|> htmlentities(?)
|> explode(?);
See it in action at 3v4l.org.
Thanks to Larry Garfield, Joe Watkins, Levi Morrison, and Paul Crovella for the RFC and the implementation.
-
Nikita has finalized the implementation of the property accessors, and the proposal is now officially under discussion.
The bottom line is that traditional getters and setters are not convenient to use, and the magic methods __get
and __set
are not specific. The new accessors are meant to fix these issues.
The syntax is inspired by C#:
class Foo {
public $prop {
get { /* ... */ }
set { /* ... */ }
}
}
You can use them to implement read-only properties:
class User {
public string $name { get; }
public function __construct(string $name) {
$this->name = $name;
}
}
And you can specify asymmetric access, i.e. make them public or private separately for reading and writing:
class User {
public string $name { get; private set; }
...
}
Or you can use them as full-fledged methods for validation or other actions:
class Foo {
public int $bar {
get {
error_log('Getting $bar');
return $this->bar;
}
set {
assert($bar > 42);
$this->bar = $bar;
}
}
}
-
Union types were added in PHP 8.0, and this RFC proposes to add intersection types.
The syntax is TypeA&TypeB
, and it means that the variable must be both instanceof TypeA
and instanceof TypeB
.
Details
class A {
private Traversable&Countable $countableIterator;
public function setIterator(Traversable&Countable $countableIterator): void {
$this->countableIterator = $countableIterator;
}
public function getIterator(): Traversable&Countable {
return $this->countableIterator;
}
}
The proposal is called “pure intersection types” because combinations with union types are not supported and are being left for future consideration. Aliases for complex types are also being left for the future.
-
There is a tick mechanism in PHP: declare(ticks=1)
. It was originally needed to track pcntl signals. Now you can use pcntl_signal()
and pcntl_async_signals()
for this, which is why there’s been a suggestion to deprecate ticks in PHP 8.1 and remove them completely in PHP 9.
-
The author of this RFC proposes a final
modifier for constants, so that they cannot be overridden in child classes.
Details
class Foo
{
final public const X = "foo";
}
class Bar extends Foo
{
public const X = "bar";
}
// Fatal error: Bar::X cannot override final constant Foo::X
Fun fact from RFC: constants in interfaces are already final.
- A couple more links for those who would like to start contributing to PHP source:
If you have any interesting or useful links to share via PHP Annotated, please leave a comment on this post or send me a tweet.