PHP 8.0: New Stringable interface

Version8.0
TypeNew Feature

PHP 8.0 adds a new interface named Stringable, that indicates any classes implementing the Stringable interface implement a __toString(): string magic method.

To provide forward compatibility, PHP engine automatically adds the Stringable interface to all classes that implement a __toString() method.

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

The most common use case would be a strict type inside a function/method before it attempts to use a string function.

class Foo {
    public function __toString(): string {
        return 'FooBar';
    }
}

function safePrint(string|Stringable $input): void {
    echo htmlspecialchars((string) $input);
}

The safePrint function can use Union Types to indicate and enforce that it accepts scalar string types, or an object of a class that implements Stringable interface.

Optional to declare implements \Stringable

If a class implements a __toString method, PHP automatically considers that it implements the Stringable interface. It is not required, but possible to explicitly declare it.

class Foo implements \Stringable{
    public function __toString(): string {
        return 'FooBar';
    }
}

Checking string capabilities

With both scalar string type and the new Stringable interface, it is now possible to safely use string functions in an application that types are enforced.

$foo instanceof \Stringable

instanceof checks will return true for classes that implement __toString method with or without explicit implements \Stringable declaration.

class Foo {
    public function __toString(): string {
        return 'FooBar';
    }
}
$foo = new Foo();
var_dump($foo instanceof Stringable); // true

Note that instanceof currently requires an object, and does not accept scalar variables yet.

class_implements($foo)

class_implements function will correctly return that a given object from a class that has a __toString() method with or without an explicit implements \Stringable declaration will return Stringable as one of the interfaces the class implements.

class Foo {
    public function __toString(): string {
        return 'FooBar';
    }
}
var_dump(class_implements(new Foo())); 
// array("Stringable" => "Stringable")

is_string($foo)

The is_string function checks the type of the variable and return true only if the type of the parameter provided is string. Because objects from classes that implement __toString are objects, is_string() function returns false on objects even if they comply with Stringable interface with or without explicit declaration.

class Foo {
    public function __toString(): string {
        return 'FooBar';
    }
}
var_dump(is_string(new Foo())); // false

strict_types = 1 behavior

Stringable objects will be evaluated to strings with __toString when strict types are not enforced. If strict typing is enforced (with declare(strict_types=1) at the top of the file), an explicit string cast is required.

declare(strict_types=1);
class Foo {
    public function __toString(): string {
        return 'FooBar';
    }
}

function safePrint(string|Stringable $input): void {
    echo htmlspecialchars($input);
                        //^^^ No string cast 
}
safePrint(new Foo());
// Fatal error: Uncaught TypeError: htmlspecialchars(): Argument #1 ($string) must be of type string, Foo given in ...:...

In the snippet above, strict types are enforced. htmlspecialchars function only accepts string parameters. In case an object of Stringable interface is passed, PHP will refuse to accept it even though the object implements Stringable interface.

When strict types are enabled, make sure to cast string|Stringable values to strings with (string) $input.

Backwards Compatibility Impact

It is trivial to bring the new Stringable interface to PHP versions prior to 8.0. However, note that unless the class explicitly declares implements \Stringable, PHP versions prior to 8.0 will not provide the string-capability checks as mentioned above.

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

class MyStringCapableClass implements Stringable {
    public function __toString(): string {
        return 'Hello World';
    }
}

For the compatibility for prior PHP versions, the Stringable class must be added, and all classes providing string capabilities must explicitly declare that they implements \Stringable.

Related Changes


RFC Discussion (2017) Discussion (2020) Implementation