PHP 7.1:是否有匹配“字符串”和“实现 __toString() 的对象”的本机接口?

Lio*_*nel 8 php interface type-hinting php-7

我们有对象实现__toString()

class Foo {
    public function __toString()
    {
        return 'bar';
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我们有返回string或实现的对象的函数__toString(),就像上面的例子。

string对字符串使用返回类型当然有效:

function getString():string {
    return 'Works!';
}
Run Code Online (Sandbox Code Playgroud)

返回类型的对象Foo不起作用,因为它不是string

function getString(Foo $foo):string {
    return $foo; // Fatal TypeError!
}
Run Code Online (Sandbox Code Playgroud)

是否有任何 PHP 接口可以用来键入提示string和实现该未知接口的对象,例如Printableor Stringable(lol)?

目标是能够返回string实现特定接口的 或 对象(这将强制实现__toString)。

IMS*_*SoP 8

简单的答案是“不”——没有内置的“可串接”提示,尽管过去偶尔有人建议过。

从 PHP 8.0 开始,将支持“联合类型”,因此string|Stringable将表示“astring或 an instanceof Stringable”。但是,没有像 那样的接口Stringable,所以这不能用于检测 的实现__toString

造成这种情况的部分原因,以及您需要问的设计问题,是您在这里实际代表的是什么合同?从调用代码的角度来看,不能保证返回值实际上可以直接用作字符串 - 有许多操作对于字符串和对象的行为会有所不同,或者接受字符串但不接受自动投射对象。因此,这种提示实际上唯一保证的就是(string)$foo给出一个字符串。

所以你有几个选择:

  • 正如Stefan 所说,总是返回一个对象,实现一些接口Stringable。如果函数想要返回一个字符串,它会首先将它包装在一个简单的对象中。
  • Stringable想出一个更有意义的接口来返回,而不是泛型;例如,也许您实际返回的是某物Loggable。这样,包装字符串可以给您带来更多具体的好处:您可以向接口添加其他方法,并且调用代码在调用这些方法之前不需要进行“对象或字符串”检查。
  • 如果调用代码只是将返回值用作字符串,则根本不要返回该对象。将该函数标记为返回string,并在返回之前将任何对象转换为字符串。
  • 如果期望调用代码检查返回值并对不同类型的对象执行不同的操作,则根本不要限制返回类型。在 PHP 8 中,您可能想要添加联合类型,但前提是有一个简短的可能性列表;无论如何,过于宽泛的返回类型几乎不能用作合同。

  • 根据[PHP 8迁移指南](https://www.php.net/manual/en/migration80.new-features.php#migration80.new-features.core.others),将会有一个新的界面`如果类具有 __toString() 方法,则会自动实现 Stringable 。因此,当 PHP 8 发布时,您可以将新接口与 Union Types 结合起来并执行 `function myFunc() : Stringable|string { ...`。 (2认同)

dec*_*eze 2

字符串和对象实现__toString是不可互换的,例如$s[1]在对象上会失败(除非它实现了一些其他魔术方法)。在参数无论如何都被强制为字符串的上下文中,对象可能是有效的替代品,但这并不适用于您可以对字符串执行的所有可能的操作。所以,不,没有原生接口,因此您也不应该混合这些类型。