为什么从__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()
方法调用。
我发现简单的解决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表示,没有理由使这种行为失败。