I recently began to develop in php5 in an object oriented way and I’m stuck at something. I would really appreciate your help/recommendations.
Bear with me in this since it ended up in a mess 🙁
This is my scenario (hope I can elaborate on this clearly): I have two dynamic classes, Client and Supplier which use methods of a static class called Vocabulary. Vocabulary is a class that pulls vocabulary terms from a source which can be: plain text file, mongodb database or mysql database. An entry in a configuration file determines which of the
aforementioned three types of sources the application will use.
class Client {
public function foo() {
...
Vocabulary::getTerm();
...
}
...
}
class Supplier {
public function bar() {
...
Vocabulary::getTerm();
...
}
...
}
class Vocabulary {
public static function useVocab($vocab) {
$_SESSION['vocab'] = $vocab;
}
public static function getTerm($termKey) {...}
...
}
I planned to create Vocabulary child classes for each of the types I want to support, for example: Vocabulary_file, Vocabulary_mongodb and Vocabulary_mysql.
Vocabulary_file will override its parent useVocab() because it needs to perform additional operations appart from setting the $_SESSION variable, but
Vocabulary_mongodb and Vocabulary_mysql don’t need to override their useVocab() parent method (they just need the $_SESSION variable set).
All three Vocabulary “child” classes will override getTerm() method.
The following is what I tried and this is the mess I ended up with 🙁
- For Vocabulary_mongodb and Vocabulary_mysql, since useVocab() doesn’t exist but is inherited from Vocabulary, “method_exists()” returns true and that call
causes an infinite loop. - I looks weird both calling the child explicitly in Vocabulary and calling the parent:: in the child class.
After lots of cups of coffee I have exhausted all my wits and my brain is damaged.
// Class Vocabulary modified to make it call the desired "child" class too
class Vocabulary {
// This would execute "child" class method
private static function _callChild($method, $args) {
$child_class = 'Vocabulary_' . Config::$vocab['type']; // Config::$vocab['type'] can be: file, mongodb or mysql
if (method_exists($child_class, $method)) {
return call_user_func_array($child_class . '::' . $method, $args);
} else {
return false;
}
}
public static function useVocab($vocab) {
$_SESSION['vocab'] = $vocab;
self::_callChild(__FUNCTION__, compact('vocab'));
}
public static function getTerm($termKey) {
$termKey = strtolower($termKey);
self::_callChild(__FUNCTION__, compact('termKey'));
}
...
}
class Vocabulary_file extends Vocabulary {
public static function useVocab($vocab) {
parent::useVocab($vocab);
// some specific stuff here
}
public static function getTerm($termKey) {
parent::getTerm($termKey);
// some specific stuff here
}
}
class Vocabulary_mongodb extends Vocabulary {
public static function getTerm($termKey) {
parent::getTerm($termKey);
// some specific stuff here
}
}
class Vocabulary_mysql extends Vocabulary {
public static function getTerm($termKey) {
parent::getTerm($termKey);
// some specific stuff here
}
}
I would like to know how can I design the Vocabulary classes in order to keep the Vocabulary::… like calls in Client and Supplier and let Vocabulary know which child class use for the type configured in “Config” class.
Any advice will be greatly appreciated.
Cheers
If you’re using all
staticmethods, you may as well not use OOP at all, it’s basically all just global function calls. If you want inheritance with polymorphism to work, you pretty much need to instantiate your classes. The polymorphism then comes from the fact that the instantiated objects can be anything, but you’re calling the same methods on them. E.g.:You can use this polymorphic like this:
This is how polymorphism is really useful. The interface (
getTerm($termKey)) is defined and unchanging between classes, but the specific implementation changes. If your code is hardcoding calls toVocabulary::getTerm(), that’s not polymorphism. With your structure you’re also violating an important OO design rule: The parent does not know about its children, and it does not interact with its children. The children override functionality of the parent, not the other way around.You also shouldn’t use the
$_SESSIONas a form of global storage. Keep objects self contained.