在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();
}
此函数仅接受现有模块作为参数.因此,您无法使用标准require/include,但模块需要在使用前进行实例化.您也可以将它放入模块加载器函数中:
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();