ID: 38018 User updated by: php dot bugs at login dot hedim dot ch Reported By: php dot bugs at login dot hedim dot ch -Status: Bogus +Status: Open Bug Type: Class/Object related -Operating System: FreeBSD +Operating System: irrelevant PHP Version: 5.1.4 New Comment:
Thank you for your response. While I admit that the code example I gave was confusing, I believe it is not bogus. It is true that there is only one call to __destruct with the changed code, but it's the wrong one. The correct call to __destruct has disappeared for a different reason. This is what happens with the changed code: Because the Foo instance #1 is assigned to $var, it would only be destructed when $var goes out of scope or (as in this case) when the script terminates (normally). When unserializing $str, __wakeup is called on the unserialized Foo instance #2 and throws an exception. Then, __destruct is called on Foo instance #2. This is imho wrong because Foo instance #2 doesn't really exist. The exception indicates it could not be reconstructed, just like an exception from __construct does. If Foo instance #2 doesn't really exists, there is nothing to destruct and __destruct should not be called. The correct call to __destruct on Foo instance #1 doesn't happen anymore because the above exception terminates the script with a fatal error. Wrapping a try { } around the unserialize would bring the call to Foo #1's __destruct back. To prove this, I have extended the reproduce code (see below) to also print out which object is destructed. The point is this: If __destruct is not called for objects that throw an exception from __construct, then it should not be called either for those that throw an exception from __wakeup. In both cases, the object "could not be (re-) constructed", therefore there is nothing to destruct. I hope this makes things clearer and I apologize for the confusing description and code example before. Thank you for looking into this matter again. Extended reproduce code: ------------------------ class Foo { function __wakeup() { throw new Exception; } function __destruct() { echo "hello from $this's destructor\n"; } } $var = new Foo; echo "$var\n"; $str = serialize($var); unserialize($str); Expected result: ---------------- Object id #1 Fatal error: Uncaught exception 'Exception' [...] No output from any destructor. The exception terminates the script before any object can be destructed. Actual result: -------------- Object id #1 hello from Object id #2's destructor Fatal error: Uncaught exception 'Exception' [...] Previous Comments: ------------------------------------------------------------------------ [2006-07-05 21:36:24] [EMAIL PROTECTED] Change your code to this: $var = new Foo; $str = serialize($var); unserialize($str); and voila - no second destructor call. The first destructor is called for the temporary var. ------------------------------------------------------------------------ [2006-07-05 20:31:32] php dot bugs at login dot hedim dot ch Description: ------------ If __wakeup threw an exception when unserializing an object, __destruct is called on that object. For the same reasons as __destruct is not called if __construct threw an exception (see bug #29368), it should not be called here either. Reproduce code: --------------- class Foo { function __wakeup() { throw new Exception; } function __destruct() { echo "hello from destructor\n"; } } unserialize(serialize(new Foo)); Expected result: ---------------- hello from destructor (from the destructor of the object to be serialized) Actual result: -------------- hello from destructor (from the destructor of the object to be serialized) hello from destructor (from the destructor of the object that fails to unserialize) ------------------------------------------------------------------------ -- Edit this bug report at http://bugs.php.net/?id=38018&edit=1