This RFC introduces a new Stringable interface that is automatically added to classes that implement the __toString() method.

Goal 1. is to allow using the string|Stringable union type in PHP 8, to accept both strings and objects that implement __toString() . This is critically missing currently, on codes that deal with stringable objects: they can't be made type-safe.

Classes that implement __toString() can also declare the interface explicitly. Classes that don't declare the interface explicitly will still declare it implicitly. This allows both forward compatibility and backward compatibility: using a polyfill, classes can declare the interface on PHP 7; and on PHP 8, classes that don't do so will still be compatible with the string|Stringable union type.

Once a polyfill becomes widely available (e.g. as part of symfony/polyfill-php80), code style checkers could be able to enforce declaring the interface when __toString() is declared explicitly, for people that prefer doing so.

Here is the stub declaration of the interface:

interface Stringable { public function __toString ( ) : string ; }

Because it adds the string return type, this interface has the potential to force a BC break on any existing libraries that want to adopt it.

In order to ease forward and backward compatibility, this RFC also proposes to automatically add the return type at compile time when a __toString() method doesn't do it explicitly already. Returning a string is already enforced by the engine so this doesn't change any semantics.

This way, code moving to PHP8 won't be forced to add the return type explicitly (which would break BC on their side), and code in PHP < 8 can adopt a polyfill interface immediately (one that doesn't declare the return type for the same BC reasons.)

Providing an easy forward-path is the second goal of this RFC .

For reference, here are some annotations in Symfony, added by contributions from real-world use cases and that currently cannot be expressed precisely enough using any union types in PHP 8.