ramblings on PHP, SQL, the web, politics, ultimate frisbee and what else is on in my life
back

__toString() or not __toString()?

The __toString() belongs to the family of methods and functions called "magic functions". They are magic because for the most part they do not get called explicitly but rather intercept operations. Unfortunately there are limits to its magic, specifically the only "context" the method is aware of is its design contract: to return a string. But its not clear what purpose that is. Should this be for some internal debugging or logging purposes? There one would be most interested in internal identifiers and object state. Is it for some frontend UI where the user will most likely be interested in some textual identifier that isn't too long as to not clutter the UI. There in lies the dilemma in the magic, while useful there is no way to ensure that the given context is passed on.

A very extreme solution would be to simply first set a context on the object before using __toString() but at that point one could just as well call another method. As such I think this method can reasonably only be used for one of the two purposes within a given code base. Now the question is which of the two should it be?

One could make the argument that output for UI purposes will mostly be done inside a template. There one would prefer to limit logic as much as possible. Furthermore it would be great to ensure consistent output across the entire UI and it seems quite useful to leverage __toString() to ensure just that. That being said even there things could get complicated when dealing with translations which might be managed by the object. Additionally there might be cases where one wants a longer representation and others where one needs a shorter one. So the issue of consistent output will likely need to be dealt with in another matter anyway.

The other use case could be for internal purposes like debug messages or logging. Often code deals with generating errors has the non trivial task of figuring out to do with whatever broken information it got. So here it could also be quite useful to be able to just serialize an object and its pertinent aspects with as little knowledge about the objects class as possible. However in the real world I keep seeing debug code that first checks if __toString() is defined and if so its called explicitly and if not some other logic is used to generate a meaningful message. As such __toString() is not really all that magic. It could be any other method name just as well since everything is called manually without some magic interception. It would of course all be different if we could all rely on there being a useful __toString() method for every object and so we could just embed any scalar and object without care into a debug message knowing that it will add a useful representation of the variable into the log message.

I posed this question on twitter and there is a lively discussion going on there.

Update:
The gist of the comments on twitter is .. people are pretty evenly split between only using __toString() for UI output and only using it for internal purposes.

Comments



Use with care

The __toString() method is a very nice addition to PHP. However, as with all methods - only use it when it makes sense, and not because it exists. If it is not immediately obvious what a string representation of an object would be, better use alternative method names that are more descriptive (for example 'name', 'id', 'source', 'contents')

However, if you create classes with names like "EmailAddress", "IpAddress" or "Url", most developers will agree on the string representation. Adding a __toString() method then makes great sense, and results in nice code, in which you can use an $email variable as if it's a string, but also access its properties with calls as $email->username(), $email->hostname(), $email->valid(), etcetera.

For classes for which it is not obvious what a __toString() method would return (like 'Template', 'EventHandler', 'DatabaseConnection') - you better not use __toString().

Re: __toString() or not __toString()?

I love __toString(), and magic methods in general. I use them a lot in my projects, such as Brickrouge, a framework to create HTML elements, or my DateTime library.

I often create objects that implement __toString() to represent complex strings such as HTML elements, dates, translatable string, HTTP headers, and many more. And I like this to be transparent as well. For example:


<?php
$response->headers['Cache-Control'] = 'public, max-age=3600, no-transform';

echo $response->headers['Cache-Control']; // public, max-age=3600, no-transform
echo $response->headers['Cache-Control']->cacheable; // public
echo $response->headers['Cache-Control']->max_age; // 3600
echo $response->headers['Cache-Control']->no_transform; // true

$response->headers['Cache-Control']->no_transform = false;
$response->headers['Cache-Control']->max_age = 7200;

echo $response->headers['Cache-Control']; // public, max-age=7200
?>

or:


<?php
use ICanBoogie\DateTime;

date_default_timezone_set('EST'); // set local time zone to Eastern Standard Time

$time = new DateTime('now', 'Europe/Paris');

echo $time;                             // 2013-02-03T21:03:45+0100
echo $time->zone;                       // Europe/Paris
echo $time->zone->offset;               // 3600
echo $time->zone->location;             // FR,48.86667,2.33333
echo $time->zone->location->latitude;   // 48.86667
?>

__toString() FTW !

Re: __toString() or not __toString()?

This is an internal method and should not be used for object representation. (For serialization implement Serializable).

That being said, note that it's main idea is to be an unique identifier in string format of the object; it's used in sorting functions.

Please remember to separate your concerns for data state and presentation.

I also don't see the need for this in debugging if you debug properly.

Re: __toString() or not __toString()?

I quote Kent Beck and his definition of the "Debug Print Method" implementation pattern: "Use toString() to print useful debugging information." [Beck. Implementation Patterns. 2007, p. 76]

This can easily be translated from the Java world to PHP:
"Use __toString() to print useful debugging information."

Re: __toString() or not __toString()?

I think Emiel has it exactly right. toString() makes sense for cases where the string version of an object is intuitively obvious and deterministic. If there's any question or conditional logic around what that stringified version would be, use something more explicit.

(Even then it doesn't always fit; we use it in Drupal's query builders in our DB layer, and it is a good fit about 97% of the time. :-) )

I wouldn't ever use it for debug information. var_dump() and friends are more useful.

Re: __toString() or not __toString()?

In my current project (non PHP) all ".ToString()" output is one-line. I don't know if this is a convention and who enforce this but i like it.