为什么不能从__toString()中抛出异常?
class a
{
public function __toString()
{
throw new Exception();
}
}
$a = new a();
echo $a;
上面的代码产生了这个:
Fatal error: Method a::__toString() must not throw an exception in /var/www/localhost/htdocs/index.php on line 12
我被指向http://php.net/manual/en/migration52.incompatible.php描述了这种行为,但为什么呢?有没有理由这样做?
这里的任何人都知道吗?
在bug跟踪器上,php-dev-team像往常一样只是看手册:http://bugs.php.net/50699
答案 0 :(得分:45)
经过几次搜索,我发现了这一点,其中说:
Johannes解释说没有办法确保Zend Engine 正确处理强制转换为字符串期间抛出的异常,并且除非Engine的大部分内容不会改变被重写。他补充说,过去曾就此类问题进行过讨论,并建议Guilherme检查档案。
上面引用的Johannes是PHP 5.3发布管理器,所以它可能是“官方”的解释,因为您可能会发现PHP为什么会这样做。
该部分继续提及:
奇怪的是,
__toString()
会接受trigger_error()。
因此,__toString()
内的错误报告并非全部丢失。
答案 1 :(得分:10)
我的猜测是__toString
是hackish,因此存在于典型堆栈之外。因此,抛出的异常将不知道该去哪里。
答案 2 :(得分:8)
为了回应接受的答案,我提出了一种(或许)更好的方法来处理__toString()
内的异常:
public function __toString()
{
try {
// ... do some stuff
// and try to return a string
$string = $this->doSomeStuff();
if (!is_string($string)) {
// we must throw an exception manually here because if $value
// is not a string, PHP will trigger an error right after the
// return statement, thus escaping our try/catch.
throw new \LogicException(__CLASS__ . "__toString() must return a string");
}
return $string;
} catch (\Exception $exception) {
$previousHandler = set_exception_handler(function (){
});
restore_error_handler();
call_user_func($previousHandler, $exception);
die;
}
}
这假定定义了一个异常处理程序,大多数框架就是这种情况。与trigger_error
方法一样,执行此操作将违反try..catch 的目的,但仍然比使用echo
转储输出要好得多。此外,许多框架将错误转换为异常,因此trigger_error
无论如何都不会工作。
作为额外的奖励,您将获得完整的堆栈跟踪,就像正常的异常和您选择的框架的正常开发行为一样。
在Laravel中工作得非常好,而且我非常确定它可以在几乎所有现代PHP框架中工作。
相关截图:
note :在此示例中,output()
方法调用了__toString()
。
答案 3 :(得分:1)
从php 7.4开始,似乎允许从__toString()引发异常。我进行了php7.2兼容性检查,并说了这一点,并指出了教义StaticReflectionClass和StaticReflectionProperty。
的更多信息答案 4 :(得分:-1)
我认为这一决定的理由从未公布过。看起来像是一些内部架构限制。
在更抽象的层面上,它是有道理的。对象应该能够返回自身的字符串表示,没有理由让这种操作失败。
答案 5 :(得分:-1)
我找到了简单的解决方案:
当错误转换为字符串时,只返回__toString中的非字符串类型:NULL,FALSE甚至异常。
这将导致这样的输出(在php -a interactive SHELL中):
Catchable fatal error: Method MyClass::__toString() must return a string value in php shell code on line 1