В PHP невозможно переписать функцию, которую вы ранее определили.
Таким образом, модули стоят друг на друге, и один модуль препятствует работе другого.
На самом деле модули должны использовать функции с одинаковыми именами, в то время как они должны быть в состоянии сосуществовать рядом друг с другом.
Это можно сделать, переместив код модулей в собственные классы. Один модуль - это один класс.
Затем вы можете определить интерфейс с функциями, которые должны обеспечивать ваши классы модулей. Поэтому модули должны иметь упрощенный интерфейс - например, каждый модуль имеет функцию install()
и uninstall()
- просто определите объектный интерфейс , сначала указав необходимые функции модуля:
module_definitions.php
interface Module {
public function install();
public function uninstall();
}
mod_Module1.php:
class Module1 implements Module {
public function install() {...}
public function uninstall() {...}
}
mod_Module2.php:
class Module2 implements Module {
public function install() {...}
public function uninstall() {...}
}
После этого, когда одна из ваших подпрограмм должна иметь дело с каким-либо модулем, вы можете заставить эту функцию требовать модуля:
function module_install(Module $module) {
$module->install();
}
Эта функция будет принимать только существующий модуль в качестве параметра. Таким образом, вы не можете использовать ваши стандартные требования / включения для этого, но модули должны быть созданы перед использованием. Вы также можете поместить это в функцию загрузчика модулей:
function module_require($moduleName) {
$class = $moduleName;
if (!class_exists($class) {
$file = sprintf('mod_%s.php', $moduleName);
require $file;
if (!class_exists($class)) {
throw new DomainException(sprintf('Invalid Module File %s for Module %s.', $file, $moduleName));
}
}
}
Как получить доступ к функциям модулей?
Теперь осталось только получить доступ к самому модулю.
Вы можете создать переменную глобального массива, содержащую все модули:
// Define existing modules
$modules = array('Module1', 'Module2');
// Require the modules
array_map('module_require', $modules);
// instantiate each module:
$moduleInstances = array_map(function($module){return new $module;}, $modules);
// map modules name (key) to it's module instance:
$modules = array_combine($modules, $moduleInstances);
// access module by name:
$modules['Module1]->install();
Однако у этого есть некоторые проблемы. Например, все модули необходимо загружать одновременно, но вам может не понадобиться использовать все модули. Или представьте, что вы перезапишите глобальный массив $modules
, все модули будут потеряны.
Чтобы предотвратить все это и обеспечить больший контроль и более легкий доступ к модулям, это можно отнести к собственному классу, который позаботится обо всех деталях. Как регистр, который знает, какие модули загружены или нет, регистрирует их по мере необходимости.
Для следующего я предполагаю, что модуль может существовать только один раз. Если объект может существовать только один раз, его часто называют Singleton . Итак, мы обернем управление загрузкой и предоставлением модуля по его имени в собственный класс, который имеет дело с деталями:
class Modules {
private $modules = array();
private static $instance;
// singleton implementation for Modules manager
private static function getInstance() {
if (null === Modules::$instance) {
Modules::$instance = new Modules;
}
return Modules::$instance;
}
// singleton-like implementation for each Module
public function get($moduleName) {
if (!isset($this->modules[$moduleName]) {
module_require($moduleName);
$newModule = new $moduleName();
if (! $newModule instanceof Module) {
throw new DomainException(sprintf('Not a Module: %s', $moduleName));
}
$this->modules[$moduleName] = $newModule;
}
return $this->modules[$moduleName];
}
// get a module by name
public static function get($moduleName) {
return Modules::getInstance()->get($moduleName);
}
}
Поместите этот класс также в module_definitions.php, который всегда должен быть включен в ваше приложение.
Поэтому, когда вам нужно получить доступ к модулю, вы можете сделать это сейчас, используя статическую функцию get с именем модуля:
Modules::get('Module1')->install();
Modules::get('Module2')->install();