php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #53648 Allow __toString() to throw exceptions
Submitted: 2011-01-04 14:45 UTC Modified: 2019-06-23 08:08 UTC
Votes:98
Avg. Score:4.5 ± 0.8
Reproduced:86 of 91 (94.5%)
Same Version:28 (32.6%)
Same OS:14 (16.3%)
From: clicky at erebot dot net Assigned: nikic (profile)
Status: Closed Package: Class/Object related
PHP Version: 5.3.4 OS:
Private report: No CVE-ID: None
View Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
If you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: clicky at erebot dot net
New email:
PHP Version: OS:

 

 [2011-01-04 14:45 UTC] 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

Patches

exception-support-in-__toString (last revision 2011-01-04 13:46 UTC by clicky at erebot dot net)

Pull Requests

Pull requests:

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2011-11-10 04:05 UTC] 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;
 [2012-12-04 12:57 UTC] 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.
 [2012-12-04 16:41 UTC] nikic@php.net
@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
 [2012-12-04 17:15 UTC] benjamin dot morel at strictcoding dot co dot uk
@nikic: too bad, I did not imagine that this was a problem with PHP internals, but 
rather an architectural choice. Can we keep this feature request open, until 
someone finds a solution? It would be good to keep this as a target!
 [2012-12-05 01:13 UTC] aharvey@php.net
-Status: Open +Status: Suspended
 [2012-12-05 01:13 UTC] aharvey@php.net
Suspending: as Stas explained in the linked e-mail thread, it's "pretty hard" to do in the current engine.

Should there ever be a Zend Engine 3, however, this could be revisited.
 [2014-09-08 09:25 UTC] benjamin dot morel at gmail dot com
By the way, it's interesting to note that calling __toString() manually works fine:

class A {
    public function __toString() {
        throw new Exception();
    }
}

echo (new A); // fatal error
echo (new A)->__toString(); // exception

Still no news on that issue, 2 years later? It's a very big blocking issue for doing interesting things in modern frameworks.
 [2015-03-14 19:46 UTC] ianbytchek at gmail dot com
Any chance to account for this in PHP 7? I've read that many things in the core are being re-written / -factored. Would now be the right time to look into this?
 [2015-03-29 09:31 UTC] benjamin dot morel at gmail dot com
Now would be the time indeed! Could a core developer comment on this issue?
 [2015-03-29 09:41 UTC] benjamin dot morel at gmail dot com
Note that, for what it's worth, starting from version 3.4.1, HHVM allows __toString() to throw exceptions:

http://3v4l.org/jFfUh

Do notice also that miraculously, PHP 5.0 and 5.1 did allow __toString() to throw exceptions! How is that even possible?
 [2015-05-27 17:01 UTC] aharvey@php.net
-Status: Suspended +Status: Open
 [2015-05-27 17:01 UTC] aharvey@php.net
Reopening, although this will require an RFC (and, realistically, a PR) to proceed against a later 7.x version.
 [2017-12-01 12:55 UTC] simohe at besonet dot ch
Forbidding to throw errors is a problem when generating proxy classes in doctrine.

See https://github.com/doctrine/common/issues/824
 [2019-02-26 18:00 UTC] carusogabriel@php.net
A PR was created for that https://github.com/php/php-src/pull/3887, that will be voted as an RFC
 [2019-02-27 17:50 UTC] carusogabriel@php.net
The following pull request has been associated:

Patch Name: Allow throwing from __toString()
On GitHub:  https://github.com/php/php-src/pull/3887
Patch:      https://github.com/php/php-src/pull/3887.patch
 [2019-05-15 11:05 UTC] nikic@php.net
-Assigned To: +Assigned To: nikic
 [2019-06-23 08:08 UTC] nikic@php.net
-Status: Assigned +Status: Closed
 [2019-06-23 08:08 UTC] nikic@php.net
This has been fixed in PHP 7.4 by https://wiki.php.net/rfc/tostring_exceptions.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Nov 22 15:01:32 2024 UTC