The idea is to create a DOM-like tree. But there are some restrictions, that only certain types can actually contain the other.
I want to use an interface|abstract class|superclass to implement some well known js-functions as appendChild, replaceChild etc.
I'm using the classes page, block and item, where pages can contain blocks and blocks can contain either blocks or items.
Example: Page is a web page, block could be an list element and item could be an list item element.
But these objects contain more than just html-data and the concepts goes beyond just plain HTML representation. It's an overall idea of managing items, wether they have an actual representation or are just abstract objects. The concept itself works for many different hierarchies.
What I want to achieve is to reuse as much code of the parent class as possible (adding a child is basically the same for all classes) but to differ the type hints to match the allowed types to add as a child.
There are basically four ways I found out myself:
- I use an interface, which allows me to type hint to the superclass but not to change these.
- I use a superclass with public methods, so i can redefine the type hints (which is totally against usual practices when heriting preconditions).
- I use a superclass with protected methods, which seems still being quite quirky.
- I get rid of any superclass and just define almost the same class several times.
- I use a method to check for the type, despite the feature of type hints.
So, if anyone is still willing to answer I'm happy for any proposition, idea or hint, which option to choose. I hope I could describe the issue well enough.
And if there is something i missed I'm thankful to hear it ;)
Code
Superclass way (works, but breaks precondition inheriting practice)
class Base {
public|protected function appendChild(Base $child) {
// do stuff
}
}
class Block extends Base {
public function appendChild(Block $child) {
parent::appendChild($child);
}
}
Interface way (Does not work. It must not)
interface Interface1 {
public function appendChild(Base $child);
}
class Base implements Interface1 {
public|protected function appendChild(Base $child) {
// do stuff
}
}
class Block extends Base{
public function appendChild(Block $child) {
parent::appendChild($child);
}
}
Edited parts are bold