Req #53648 [Com]: Allow __toString() to throw exceptions

From: Date: Tue, 04 Dec 2012 16:41:50 +0000
Subject: Req #53648 [Com]: Allow __toString() to throw exceptions
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-175111@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=53648&edit=1

 ID:                 53648
 Comment by:         nikic@php.net
 Reported by:        clicky at erebot dot net
 Summary:            Allow __toString() to throw exceptions
 Status:             Open
 Type:               Feature/Change Request
 Package:            Class/Object related
 PHP Version:        5.3.4
 Block user comment: N
 Private report:     N

 New Comment:

@benjamin: I don't think anyone opposes this feature request, it's just too hard to
implement. Allowing __toString to throw exceptions would require any internal code doing a zval to
string conversion to be exception-safe. See also: http://markmail.org/message/lkpmpnhrvcbafhkd


Previous Comments:
------------------------------------------------------------------------
[2012-12-04 12:57:36] benjamin dot morel at strictcoding dot co dot uk

I strongly support this feature request.
I haven't read any valid supportive argument so far, for keeping this behaviour as 
it is currently.
In case someone would be worried about backward compatibility issues, this change 
could be introduced with the next major version, PHP 5.5!

I would be grateful if a member of the PHP team could review this request.

------------------------------------------------------------------------
[2011-11-10 04:05:48] dqhendricks at hotmail dot com

this problem is causing me such a headache. i'm not even trying to convert an object 
to a string and i'm getting this error. the bug become such a pain to track. i have 
an active record that lazy loads child objects through __get. so even though im just 
trying to print a property of an object that is a string, the fact that a __get is 
used to get that object, prevents me from throwing exceptions. it looks like this 
echo $activerecord->childobject->somestring;

------------------------------------------------------------------------
[2011-01-04 14:45:29] clicky at erebot dot net

Description:
------------
Currently, when casting an object with __toString() to a string, __toString() is not allowed to
throw an exception.
Trying to do so triggers an E_ERROR "Method %s::__toString() must not throw an exception".
IMHO, this is counter-intuitive, especially since calling that object's __toString() method
directly would correctly throw the exception.

I propose to allow __toString() to throw exceptions.

Note: this was already reported in http://bugs.php.net/bug.php?id=50699 but marked as
bogus with the only explanation being "__toString must not throw".
So, I'm marking this as a feature request rather than a bug, since the current behaviour seems
to be expected (though it is not documented in http://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.tostring).

I also found this entry http://stackoverflow.com/questions/2429642/why-its-impossible-to-throw-exception-from-tostring
which cites Johannes saying this requires major changes in the code. However, the article mentioned
is from 2007 and I think the limitations in ZE that prevented this to be implemented were lifted
since then.

I'm not very versed in PHP's inner workings, but attached is a tentative patch which seems
to fix this issue.

Test script:
---------------
<?php

class CustomException
extends Exception
{
}

class Foo
{
    public function __toString()
    {
        throw new CustomException('oops!');
    }
}


$foo = new Foo();
try {
    var_dump((string) $foo);
}
catch (CustomException $e) {
    var_dump($e);
}

?>

Expected result:
----------------
object(CustomException)#2 (7) {
  ["message":protected]=>
  string(5) "oops!"
  ["string":"Exception":private]=>
  string(0) ""
  ["code":protected]=>
  int(0)
  ["file":protected]=>
  string(17) "/tmp/toString.php"
  ["line":protected]=>
  int(65)
  ["trace":"Exception":private]=>
  array(1) {
    [0]=>
    array(6) {
      ["file"]=>
      string(17) "/tmp/toString.php"
      ["line"]=>
      int(71)
      ["function"]=>
      string(10) "__toString"
      ["class"]=>
      string(3) "Foo"
      ["type"]=>
      string(2) "->"
      ["args"]=>
      array(0) {
      }
    }
  }
  ["previous":"Exception":private]=>
  NULL
}


Actual result:
--------------
PHP Fatal error:  Method Foo::__toString() must not throw an exception in /tmp/toString.php on line
0
PHP Stack trace:
PHP   1. {main}() /tmp/toString.php:0


------------------------------------------------------------------------



-- 
Edit this bug report at https://bugs.php.net/bug.php?id=53648&edit=1


Thread (14 messages)

« previous php.bugs (#175111) next »