__toString() and exceptions

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

Post Reply
User avatar
m4rw3r
Forum Commoner
Posts: 33
Joined: Mon Aug 03, 2009 4:19 pm
Location: Sweden

__toString() and exceptions

Post by m4rw3r »

From PHP 5.2 and onwards it is no longer to throw Exceptions __toString() when using an object as a string (eg. in echo(), implode(), etc.).

The problem is that I have a SQL-builder which uses exceptions from __toString() if some data is missing (eg. a FROM part).
I use __toString() because it makes it a lot easier to concatenate strings with objects:

Code: Select all

$string = implode(', ', $list);
$string = ‘’;
?foreach($list as $element)?
{?
    if($element instanceof Some_class)?
    {?
        $string .= $element->getString();
?    }?
    else
?    {
?        $string .= $element;
?    }?
}
// Instead of
$string = implode('', $list);
It is both faster and easier to read (and maintain), but the problem is that I still need to throw exceptions from them.

So what I've figured so far is that I probably need to embed the error in the generated string, and then search for the error string in the generated SQL before I send it to the database:

Code: Select all

function getSQL()
{
    $sql = $this->__toString();
    self::detectError($sql);
 
    // db interaction...
}
The problem is that I also need a delimiter for this error message, any suggestions?

And if you know any other way of throwing exceptions from code which is run in __toString(), please tell.
User avatar
Ollie Saunders
DevNet Master
Posts: 3179
Joined: Tue May 24, 2005 6:01 pm
Location: UK

Re: __toString() and exceptions

Post by Ollie Saunders »

Code: Select all

function asStr($x) {
   if (method_exists($x, '__tostring')) { # false if non-object.
      return $x->__tostring();  # allows exceptions to be thrown normally.
   }
   return (string)$x;
}
 
implode(array_map($pieces, 'asStr')); # any exceptions will occur before implosion.
User avatar
m4rw3r
Forum Commoner
Posts: 33
Joined: Mon Aug 03, 2009 4:19 pm
Location: Sweden

Re: __toString() and exceptions

Post by m4rw3r »

That seems like a good solution.

I've implemented the error sending through the generated string, and it works well.
The downside is that it won't interrupt the execution until it has generated the whole string to be able to parse it.

The downsides of your method are a decrease in performance and a lot of extra method calls (eg. string concatenation).

My benchmark:

Code: Select all

function asStr($x)
{
    return method_exists($x, '__tostring') ? $x->__toString() : $x;
}
 
class Foobar
{
    function __toString()
    {
        return 'Foobar';
    }
}
 
for($i = 0; $i < 100; $i++)
{
    $a[] = 'Bar';
    $a[] = new Foobar();
}
 
 
$t = microtime(true);
for($i = 0; $i < 1000; $i++)
{
    $s = implode('', array_map('asStr', $a));
}
$t2 = microtime(true);
 
echo 'asStr: '.($t2-$t)."\n";
 
 
$t = microtime(true);
for($i = 0; $i < 1000; $i++)
{
    $s = implode('', $a);
    $p = strpos($s, 'aaaa');  // this equals the check for an error message without finding one
}
$t2 = microtime(true);
 
echo '__toString: '.($t2-$t)."\n";
Results:

Code: Select all

asStr: 7.90123105049
__toString: 1.53427004814
What do you think can got wrong if the execution is allowed to continue when an error (eg. missing WHERE part in the query, no data in UPDATE query) is encountered?
It is "only" a string builder after all, and the only probable result I can see is that it continues to parse the more complex complex queries even if the result will be discarded.

Maybe I can move the exception needing parts of the string conversion from the __toString() method, and use __toString() directly, before I concatenate it? Going to check.
Apparently calling __toString() directly before concatenating its result with the string is faster than concatenating the object with the string and letting PHP call __toString() automatically.
User avatar
Ollie Saunders
DevNet Master
Posts: 3179
Joined: Tue May 24, 2005 6:01 pm
Location: UK

Re: __toString() and exceptions

Post by Ollie Saunders »

Your embedded error idea is the kind of clever code that will cause maintainers headaches. Write code that makes your intentions obvious and is conceptually simplest.

Also "premature optimization is the root of all evil." - This quote is a cliché nowadays but no less true than when it was first used.
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Re: __toString() and exceptions

Post by josh »

In Zend Framework they catch the exception and implode() it's stack trace, returning it in the final returned string. You could also trigger a warning if you wanted to halt the flow. I think the key is they dont want you to do a lot of work in that method, in 5.3 it doesnt take arguments anymore which affects some legacy code too
Post Reply