为什么从__toString()抛出exception是不可能的?

为什么从__toString()抛出exception是不可能的?

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

经过几次search,我发现这个,它说:

Johannes解释说, 没有办法确保在强制转换为string的过程中引发的exception将被Zend引擎正确处理 ,除非引擎的大部分被重写,否则不会改变。 他补充说,过去一直在讨论这个问题,并build议吉列尔梅检查档案。

上面提到的Johannes是PHP 5.3版本pipe理器,所以它可能是“官方”的解释,你可能会发现为什么PHP的行为如此。

该部分继续提到:

__toString()会奇怪地接受trigger_error() 。

因此,在__toString()内的错误报告中,并不是所有的都会丢失。

我的猜测是__toString是hackish,因此存在于典型的堆栈之外。 那么抛出的exception就不知道该去哪里了。

为了回应接受的答案,我想出了一个(可能)更好的方法来处理__toString()exception:

 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; } } 

这假设有一个exception处理程序定义,这是大多数框架的情况。 与trigger_error方法一样, 这样做将违反try..catch的目的 ,但仍然比使用echo转储输出要好得多。 另外,许多框架将错误转换为exception,所以trigger_error无法正常工作。

作为一个额外的好处,你会得到一个完整的堆栈跟踪正常的例外和正常的开发生产行为的select框架。

在Laravel工作的非常好,我很确定它可以在几乎所有的现代PHP框架中工作。

截图相关:
注意 :在这个例子中, output()__toString()方法调用。

由Laravel异常处理程序捕获的__toString()异常

我发现简单的解决scheme

在错误转换为string时,只要在__toString中返回类似非string的types:NULL,FALSE甚至Exception。

这会导致这样的输出(在php -a交互式SHELL中):

 Catchable fatal error: Method MyClass::__toString() must return a string value in php shell code on line 1 

我不认为这个决定的理由曾经被公之于众。 看起来像一些内部的架构限制。

在更抽象的层面上,这是有道理的。 一个对象应该能够返回自己的string表示,没有理由使这种行为失败。