note 107509 added to language.oop5.magic
| From: | daan dot broekhof at gmail dot com | Date: | Tue, 14 Feb 2012 10:54:18 +0000 |
| Subject: | note 107509 added to language.oop5.magic | ||
| Groups: | php.notes | ||
| Request: | Send a blank email to php-notes+get-186121@lists.php.net to get a copy of this message | ||
Ever wondered why you can't throw exceptions from __toString()? Yeah me too.
Well now you can! This trick allows you to throw any type of exception from within a __toString(),
with a full & correct backtrace.
How does it work? Well PHP __toString() handling is not as strict in every case: throwing an
Exception from __toString() triggers a fatal E_ERROR, but returning a non-string value from a
__toString() triggers a non-fatal E_RECOVERABLE_ERROR.
Add a little bookkeeping, and can circumvented this PHP deficiency!
(tested to work PHP 5.3+)
<?php
set_error_handler(array('My_ToStringFixer', 'errorHandler'));
error_reporting(E_ALL | E_STRICT);
class My_ToStringFixer
{
protected static $_toStringException;
public static function errorHandler($errorNumber, $errorMessage, $errorFile, $errorLine)
{
if (isset(self::$_toStringException))
{
$exception = self::$_toStringException;
// Always unset '_toStringException', we don't want a straggler to be found later
if something came between the setting and the error
self::$_toStringException = null;
if (preg_match('~^Method .*::__toString\(\) must return a string value$~',
$errorMessage))
throw $exception;
}
return false;
}
public static function throwToStringException($exception)
{
// Should not occur with prescribed usage, but in case of recursion: clean out exception, return a
valid string, and weep
if (isset(self::$_toStringException))
{
self::$_toStringException = null;
return '';
}
self::$_toStringException = $exception;
return null;
}
}
class My_Class
{
public function doComplexStuff()
{
throw new Exception('Oh noes!');
}
public function __toString()
{
try
{
// do your complex thing which might trigger an exception
return $this->doComplexStuff();
}
catch (Exception $e)
{
// The 'return' is required to trigger the trick
return My_ToStringFixer::throwToStringException($e);
}
}
}
$x = new My_Class();
try
{
echo $x;
}
catch (Exception $e)
{
echo 'Caught Exception! : '. $e;
}
?>
----
Server IP: 91.199.167.223
Probable Submitter: 2001:888:1dd1:0:223:dfff:fe91:d840
----
Manual Page -- http://www.php.net/manual/en/language.oop5.magic.php
Edit -- https://master.php.net/note/edit/107509
Del: integrated -- https://master.php.net/note/delete/107509/integrated
Del: useless -- https://master.php.net/note/delete/107509/useless
Del: bad code -- https://master.php.net/note/delete/107509/bad+code
Del: spam -- https://master.php.net/note/delete/107509/spam
Del: non-english -- https://master.php.net/note/delete/107509/non-english
Del: in docs -- https://master.php.net/note/delete/107509/in+docs
Del: other reasons-- https://master.php.net/note/delete/107509
Reject -- https://master.php.net/note/reject/107509
Search -- https://master.php.net/manage/user-notes.php