I've got a couple of questions about PHP classes but they cannot be asked separately, so here I go:
I have a CMS that I am building and at the core of it there is my baseClass, logger, DB and modules classes. DB and logger are static classes so I can use them from within other objects. There are a lot of module classes that are loaded into the baseClass with:
class baseClass {
private $_modules;
public function __construct() {
logger::log("instance created.");
$this->_modules = Array()
}
public function __destruct() {
foreach($this->_modules as $name) $this->unloadModule($name);
logger::log("instance destroyed.");
}
public function loadModule($name) {
if (class_exists($name)) {
if (!isset($this->$name)) {
$this->_modules[] = $name;
$this->$name = new $name();
logger::log("module '$name' loaded.");
}
else logger::log("module '$name' already loaded.", 2);
}
else logger::log("module '$name' does not exist.", 3);
}
public function unloadModule($name) {
if (isset($this->$name)) {
unset($this->$name);
foreach($this->_modules as $id => $mod_name) {
if ($name==$mod_name) {
unset($this->_modules[$id]);
logger::log("module '$name' unloaded.");
}
}
}
else logger::log("module '$name' not loaded.", 2);
}
public function listModules() {
return $this->_modules;
}
}
$instance = new baseClass();
$instance->loadModule('moduleX');
$instance->loadModule('moduleY');
Question 1: Is my loadModule implementation a good idea or you have a better solution. Or is it possible to extend a class the other way around, so I wouldn't have to load the modules, instead their class definition would load themselves into the baseClass like:
class moduleX reverseExtends baseClass {
public function f1();
public function f2();
}
class moduleY reverseExtends baseClass {
public function f3();
public function f4();
}
$instance = new baseClass();
$instance->f1();
$instance->f2();
$instance->f3();
$instance->f4();
Or at least:
$instance->moduleX->f1();
$instance->moduleX->f2();
$instance->moduleY->f3();
$instance->moduleY->f4();
Question 2: For now I am using my logger and DB classes as static classes (I call them with logger:: and DB::) so they are accessible from any context and scope - is it possible to instantiate them and still use them inside my baseClass object but without instantiating them inside the baseClass or setting them up like this inside every class I am going to use it with:
public function __construct() {
global $logger_instance;
$this->logger = $logger_instance;
}
I've tried different methods ranging from bad as passing a reference of the original object inside the baseClass to ugly as using wrapper functions. Using references destroys my logger object when baseClass is unset and is hard to access via modules - $this->base->logger->log() - which in turn requires a reference to the baseClass object ($this->base) and kills my baseClass object on unloadModule... As for the wrapper function - I want to be able to have multiple instances of the logger object, so passing an instance identificator along with the function makes it really ugly and 'untrue' solution.
I need something like:
public function someFuncionInsideSomeClass() {
$logger->('Log something'); //or $logger('Log something') with __invoke()
//$logger here is in the global scope
}
Question 3: I want one module to be able to modify the code of another one. For example I have a database module loaded, then I load a logger module and want the logger module to integrate into the database module code without me having to mess with it's original code. Of course the logger would have to take care of the integration itself (or rather me as the coder). Simple example:
class tagCreator {
public function createTag($tag,$data) {
$tag1 = $tag;
$tag2 = '/'.$tag;
return "<$tag1>$data<$tag2>";
}
}
class styleFunctionality {
public function __construct() {
//if class is loaded (tagCreator) | load class (tagCreator)
//do some magic here to tagCreator
//tagCreator -> createTag -> add argument $style
//tagCreator -> createTag -> $tag1 += ' style="'.$style.'"'
//else issue error tagCreator does not exist
}
}
$instance = new baseClass();
$instance->loadModule('tagCreator');
echo $instance->createTag('span','some string');
// returns <span>some string</span>
$instance->loadModule('styleFunctionality');
echo $instance->createTag('span','some string','font-weight: bold');
// returns <span style="font-weight: bold">some string</span>
Note: I do not necessarily mean function overloading, I might want to change only a bit of code inside a method
Note 2: Calling $instance->createTag() is not an error - I plan on writing some fancy __call() function for baseClass to pick methods from its loaded modules
Sorry for the long topic and thanks for reading this far, I'd even appreciate an answer to only one of my questions :)
For DB and Logger, I would consider using a Singleton pattern.
<?php
class Singleton {
private static $instance;
private function __construct() {
// no-op
}
/**
* Create the instance or return the instance if it has already been created.
*
* @return object
*/
static public function get_instance() {
if (!isset(self::$instance)) {
$c = __CLASS__;
self::$instance = new $c;
}
return self::$instance;
}
}
?>
In general, you may want to look at the PHP frameworks that require PHP5 such as Kohana. And, as far as patterns and PHP goes, you may want to checkout "PHP Objects, Patterns, and Practice."
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With