Tuesday, January 24, 2006

All Exceptions Created Equal...

All exceptions are created equal. But what if you have a very good and pressing reason to serialize one to save it in a database? For instance, you had a collection of checks you wanted to run against some data, and save the results?

Ah, that's easy! serialize() was made for that! So off you trot, you make a few changes to the code, add a blank line here, a blank line there, and suddenly your code can't find the exact matches of the serialized object in the database.

HUH? What's going on? You're the exact same Exception I just threw three minutes ago, and you've sporadically broken?

It took me a while to twig. When you create an exception ($e = new Exception("foo");), it's shiny and new and listens when you do equality comparisions (==).

But things go awry: you throw a new Exception from your filter, catch it, and serialize it. You haven't remembered that...



$a = new Exception("foo");
try {
throw $a; //Line 1
} catch (Exception $e) {
throw $a; //Line 10;
}



will result in two difference traces. One saying "I was throw on on line 1", the other "I was throw on on line 10"...

Fuck oath, hello stupid coder. You've been wracking your brains wondering why every time you go off and edit a different bit of code it serializes differently; and there you have it.

How the hell do I fix it? Going to __sleep() on the job actually helps.




<?php
class DumbException extends Exception {
/**
* Cleanup anything we need before serialisation
*
* @return string[] An array of member varible names to serialize
* @see http://php.planetmirror.com/manual/en/language.oop5.magic.php
*/
public function __sleep() {
return array('string','code');
}

/**
* Compare against another DumbException for equality.
*
* Since two exceptions can be !== because the trace / line / file
* information is different, we need to do this.
*/
public function cmp(DumpException $e) {
return (serialize($e) == serialize($this));
}
}

print '<pre>';
$a = new DumbException();
$b = new DumbException();


try {
try {
throw $b;
} catch (Exception $e) {
throw $a;
}
} catch (Exception $e) {

var_dump($a === $b);
var_dump($a == $b);
var_dump($b === $e);
var_dump($b == $e);
var_dump($a === $e);
var_dump($a == $e);

var_dump($b->cmp($e));
var_dump($a->cmp($e));
}
print '</pre>';
?>

No comments: