PHP 7 严格类型对象转换为字符串

4

我有一个函数,它期望一个字符串作为输入参数:

<?php
declare(strict_types = 1);

function testXml(string $xml) {
    echo "this is a string: " .$xml;
}

当我传递一个对象给这个函数时,我希望会抛出一个类型错误。 但事实并非如此,类型为SimpleXmlElement的对象被默默转换为字符串: https://3v4l.org/lQdaZ 这是一个错误还是特性?
3个回答

6
魔术函数 __toString() 的文档所述:

__toString() 方法允许类在被当作字符串处理时决定如何响应。

因为类SimpleXmlElement实现了__toString()魔术方法,所以每次使用期望字符串的位置时都会调用它(该方法)。__toString()返回的值将代替对象。
很难判断这是一个特性还是一个错误1。函数testXml()当前期望一个字符串作为参数,但你不喜欢它悄无声息地接受一个SimpleXmlElement
如果删除其参数类型,则不再发生对__toString()的调用,函数内$xml参数的值是SimpleXmlElement对象。在echo "this is a string: " .$xml;行中发生了对__toString()的调用,即使$xml不是字符串,你也可以打印其值,这非常方便。
如果您认为这是一个错误,则echo(期望字符串作为参数)应该抱怨$xml的类型,并且不应该打印它。不太方便,对吧?

1 这不是一个错误,这就是语言发展的方式。__toString()在标量类型的类型声明之前被引入,为了不破坏现有行为,如果可能的话会调用它,而不是触发有关参数类型不正确的错误。


感谢您的详细解释,但是很遗憾,我发现它令人烦恼。 - dev0
我发现更令人不安的是,在phpunit单元测试中,该对象被转换为空字符串。 - dev0
这是一个真实的对象还是一个模拟对象? - axiac
它是一个真实的对象。 - dev0
这与__toString()无关。即使是具有__toString()方法的对象也不能传递到期望字符串的位置。 - AndreKR

3
那是因为你传递给函数的是字符串($simpleXml),而不是 SimpleXmlElement($xml)。

虽然应该补充说明,如果没有使用declare(strict_types = 1);执行OP的代码将以意外的方式工作。请参阅:https://3v4l.org/r7eL6 - k0pernikus

0

这是一个 PHP 中的特性,如果定义了对象的 __toString 魔术方法,PHP 就会调用它:

此代码需要 PHP@7:

<?php
class ClassImplementingToString
{
    public function __toString()
    {
        return "hello world";
    }
}

function foo(string $foo)
{
    echo $foo;
}

foo(new ClassImplementingToString());

将输出:你好,世界

沙盒示例


Fatal error: Uncaught TypeError: Argument 1 passed to foo() must be of the type string, object given - AndreKR
这与 __toString() 没有任何关系。即使一个具有 __toString() 方法的对象也不能被传递到期望字符串的位置。 - AndreKR
@AndreKR 你是在说php@5吗?这个答案使用的是php@7 http://sandbox.onlinephpfunctions.com/code/3e2038ceda8a2e8fe325786973c771017bf5f580 - k0pernikus
你忘记了 declare(strict_types = 1); - AndreKR

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接