views:

90

answers:

3

I want to create a sort of datamapper library, where you'd do something like this:

$users = Users::getTable();
$users->add($newUser1);
$users->add($newUser2);

Now $users contains 2 user records, but they aren't yet persisted to the database. To be efficient, I'd like to flush them all at once. I would like to have a flush() method to do this (not an issue), but I'd also like for it to happen implicitly when the $users table reference falls out of scope. Is there any reason I shouldn't do this in the destructor?

+1  A: 

Who guarantees your database is available when your destructor is called?

Garbage collectors usually do not guarantee the order of execution for destructors in object graphs, so you may not even rely on any external references. A database is even worse.

EDIT: OK, php uses ref counting instead of a generational GC, but it's still bad practice to have side-effects in destructors.

What's so bad about calling flush explicitly? Maybe users of your library simply want to let some changes evaporate.

Johannes Rudolph
Not sure if I follow, but the table would have a reference to the db connection which would guarantee its availability.
ryeguy
PHP destructors are somewhat deterministic (in that they are called as soon as the last reference goes out of scope). At least, that's my understanding...
Dean Harding
No, it doesn't. The garbage collector might have destroyed the db connection, hence your reference is invalid at destructor time. What happens if your database call throws an exception for whatever purpose? It might crash your webserver.
Johannes Rudolph
Ah, I see what you mean. I don't know if PHP gaurantees that member fields are invalidated only *after* the destuctor is called, but that would seem logical to me (that is, if the database connection is held in a member variable, then I would expect it *not* to be destructed before the parent object's destructor is called). But I'm not a PHP expert, so I don't know...
Dean Harding
I'm neither, php uses ref-counting so things might be different here (read: it might work) than I'm used to in .net.
Johannes Rudolph
@codeka: I checked with .nets FileStream how they handle Flushing in the finalizer. They certainly do flush the stream from the finalizer but special measures are taken no references are accessed.
Johannes Rudolph
+2  A: 

I would suggest a better solution would be to raise an error in your destructor if the flush() method has not been explicitly called.

In this case, it's probably better to be explicit and raising an error in the destructor ensures that you've definitely either called flush() (or "rollback" or whatever you call it). By raising an error, you also get a really in-your-face notification that something went wrong, whereas if you just do nothing, then you might not notice it.

Dean Harding
+1  A: 

There is no warranty whatsoever that the current PHP interpreter shutdown order will not change, and your database handles might be destroyed before being called. (That's why it is undocumented btw..)

crrodriguez