In Ruby, I have a DAO class, which is extended by a class that makes managing the connections easier, which is extended by a class that represents and manipulates data in a DB, which is further extended by another class. To use an animal metaphor it would look like this:
class Animal
...
end
class Mammal < Animal
...
end
class Feline < Mammal
...
end
class Cat < Feline
...
end
class Lion < Cat
...
end
...
In PHP, there is __destruct
method that runs when you destroy/delete a class. And should that class extend another class, you simply add parent::__destruct()
to the class's __destruct
method like this:
public function __destruct() {
// Clean up code for this class here
...
// Execute clean up code for Parent class
parent::__destruct();
}
I could have a similar method for all the classes except Animal
. Since it doesn't extend anything, the parent::__destruct();
line is no longer valid.
However, as I understand it, Ruby doesn't have a method like this for its objects. A finalizer can be set, but I decided to just put in a cleanup
method I can call whenever I want to destroy/delete a class. That would take care of anything that needed doing prior to my setting the class to nil
.
This raises a new problem though. If the method is always named cleanup
and I call lion_instance.cleanup
, I assume it calls the Lion#cleanup
. How then to get it to call the cleanup
in class Cat
and then Feline
and on down the chain?
Or is this a wrong approach and you have a better idea?
Well since no one answered your question about the method moving its way up the inheritance chain...
Within a method, you can access the superclass's method of the same name by calling super.
You can use ObjectSpace.define_finalizer
Something like:
The Ruby idiom for this is to yield to a block which does work, and when the block returns, do cleanup. Ruby's built-in "File.open" does this:
When the block ends, the file is closed for you, without you having to do anything. This is an excellent idiom. Here's how you might implement something like that:
And to use it:
Foo#close
will be caused automatically after theend
This will work with subclassing as well. That's because class methods are inherited just as are instance methods. Here's the superclass:
and two derived classes:
to use:
If you really need to make sure that cleanup happens no matter what, then use an ensure clause in the class method:
This way, cleanup happens even if there is an exception in the block.