In the progress of writing a little framework for a web app I came along some difficulties in making classes communicate with each other.
Environment
I have an abstract class called LizardModule, that should be extended by all the single modules of the web-app. This class has a final protected function registerController(...)
, that creates a new Object of the type LizardController
. This is, as it sounds, based on the idea of MVC. With the final protected function registerFunction(...)
, modules can register functions for every controller. Those are stored using addFunction(...)
on the controller object. Here is what this looks like:
Example Module:
class ModuleOverview extends LizardModule {
protected function setup() {
$this->registerController(
'overview',
'App Overview'
);
$this->registerFunction(
'overview',
'myfunction',
'My Function',
array(&$this, 'theFunctionToCall')
);
}
public function theFunctionToCall() { ... Generate Content ... }
}
Module Class:
class LizardModule {
private $controllers = array();
final public function __construct() { $this->setup(); }
abstract protected function setup();
[...]
final protected function registerController($controllerSlug, $controllerName) {
if (array_key_exists($controllerSlug, $this->controllers))
return false;
$this->controllers[$controllerSlug] = new LizardController($controllerSlug, $controllerName);
}
final protected function registerFunction($controllerSlug, $functionSlug, $functionName, callable $function) {
if (!array_key_exists($controllerSlug, $this->controllers))
return false;
$this->controllers[$controllerSlug]->addFunction($functionSlug, $functionName, $function);
}
}
This results in a lot of objects of type LizardController in different places of the app. To make all of those objects accessable, I created a singleton class LizardRouter, that should hold a reference to all of those controller objects. Therefore, the controller-object registers itself with this singleton class:
Controller Class:
class LizardController {
[...]
private $functions = array();
public function __construct($slug, $name, $menu) {
$this->slug = $slug;
$this->name = $name;
$this->menu = $menu;
LizardRouter::registerController($this);
}
public function addFunction(...) { Tested, this works. }
public function getFunctions() {
return $this->functions;
}
}
Router Class:
final class LizardRouter {
[...]
public static function getControllers() {
return static::getInstance()->controllers;
}
public static function registerController(LizardController $controller) {
static::getInstance()->controllers[] = $controller;
}
}
The Problem
The whole thing works alright for the controllers. In my interface class, I can read out all controllers and print a menu containing their names. The problem is: Whenever I access the controllers functions-array (see controller class) through the controllers-array given by the routing class, I get an empty array. I asume that somewhere a reference is not working and I am passing the actual controller object, before my module-class was able to add the functions to the controllers functions-array. But I can't figure out where exactly the problem lies. Here is an example from my interface class showing the problem:
foreach (LizardRouter::getControllers() as $controller) {
// Allways returns an empty array, even though
// the module added functions to the controller.
$controller->getFunctions();
}