我有几个关于PHP课程的问题,但不能单独询问,所以我去了:
我正在构建一个CMS,其核心是我的baseClass,logger,DB和模块类。 DB和logger是静态类,因此我可以在其他对象中使用它们。有许多模块类通过以下方式加载到baseClass中:
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');
问题1:我的loadModule实现是一个好主意还是您有更好的解决方案。或者是否可以反过来扩展一个类,所以我不必加载模块,而是将它们的类定义加载到baseClass中,如:
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();
或者至少:
$instance->moduleX->f1();
$instance->moduleX->f2();
$instance->moduleY->f3();
$instance->moduleY->f4();
问题2:目前我使用我的记录器和数据库类作为静态类(我用logger ::和DB::)调用它们,因此可以从任何上下文和范围访问它们 - 是它可以实例化它们并仍然在我的baseClass对象中使用它们但是没有在baseClass中实例化它们或者在我将要使用它的每个类中将它们设置为:
public function __construct() {
global $logger_instance;
$this->logger = $logger_instance;
}
我尝试过不同的方法,从使用包装函数将badClass中的原始对象的引用传递给丑陋。当baseClass未设置并且难以通过模块访问时,使用引用会破坏我的logger对象 - $ this-> base-> logger-> log() - 这又需要引用baseClass对象($ this-&gt ;基础)并在unloadModule上杀死我的baseClass对象...对于包装器函数 - 我希望能够拥有logger对象的多个实例,因此将实例标识符与函数一起传递使其变得非常难看并且“不真实”溶液
我需要类似的东西:
public function someFuncionInsideSomeClass() {
$logger->('Log something'); //or $logger('Log something') with __invoke()
//$logger here is in the global scope
}
问题3:我希望一个模块能够修改另一个模块的代码。例如,我加载了一个数据库模块,然后我加载一个记录器模块,并希望记录器模块集成到数据库模块代码中,而不必乱用它的原始代码。当然记录器必须处理集成本身(或者更确切地说,我作为编码器)。简单的例子:
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>
注意:我不一定是指函数重载,我可能只想更改方法中的一些代码
注意2:调用$ instance-&gt; createTag()不是错误 - 我打算为baseClass编写一些花哨的 __ call()函数,从其加载的模块中选择方法
对于这个漫长的话题感到抱歉,感谢您阅读这篇文章,我甚至感谢您回答我的一个问题:)
答案 0 :(得分:3)
对于DB和Logger,我会考虑使用Singleton模式。
<?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;
}
}
?>
通常,您可能希望查看需要PHP5的PHP框架,例如Kohana。而且,就模式和PHP而言,您可能想要签出“PHP对象,模式和实践”。
答案 1 :(得分:1)
Q1 - 我会使用autoloader function来加载课程。您可以解析类名以找出您尝试加载的类的位置和类型(例如 - 控制器,模块,插件等)。
与__get()
(在基类中)一起,如果需要,您可以调用$instance->moduleX->f1();
之类的模块。
Q2 - 我也将静态类用于这些类型的活动。除了拥有一个全局可用的变量 - 存在与其他领域的代码冲突的风险 - 你可以做的其他事情也不多。
Q3 - 有一种类似于你想要实现的东西的模式,但对于我的生活,我现在似乎无法记住它。但是它是怎么回事,你需要在你的主类中注册修饰符类。看看你如何构建你的应用程序,你可以通过查看基类模块数组,或通过将修饰符类传递给主类(tagCreator
)来实现。
但是您决定这样做,您需要修改createTag()
方法以在返回输出之前查找已加载的修饰符类(styleFunctionality
)。您的修饰符类当然需要某种标准接口供您的主类调用。
警告一下,看看你是如何将模块加载到同一个实例中的。如果两个类定义了相同的方法,则可能会发生冲突。我建议您单独访问它们,例如$this->ModuleA->aMethod()
。