2011-04-13 65 views
7

我有几个关于PHP类的问题,但他们不能单独询问,所以我来到这里:一些(高级)问题

我有我建设,并在核心CMS它有我的baseClass,记录器,DB和模块类。 DB和记录器是静态类,所以我可以在其他对象中使用它们。有很多被加载到基类与模块类:

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:是我的加载模块的实现是一个好主意,或者你有更好的解决方案。或者是有可能扩展类的其他方式,所以我也不会加载模块,而不是他们的类定义将自己加载到像基类:

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:现在我用我的记录和DB类作为静态类(我称他们与记录::和DB::)所以他们在任何情况下和范围访问 - 这可能实例他们仍然在我的baseClass对象中使用它们,但没有在baseClass中实例化它们或者像这样设置它们每一类中,我要与使用它:

public function __construct() { 
    global $logger_instance; 
    $this->logger = $logger_instance; 
} 

我已经尝试了不同的方法,从坏的传递基类中的原始对象的引用丑陋使用包装函数。当baseClass未设置并且很难通过模块访问时,使用引用会破坏我的记录器对象 - $ this-> base-> logger-> log() - 这需要引用baseClass对象($ this-> base)和杀死我的baseClass对象在unloadModule上......至于包装函数 - 我希望能够拥有多个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:调用$实例 - > createTag( )是不是一个错误 - 我打算写一些花哨 __ ()函数调用基类为挑选其加载的模块远远阅读本方法

很抱歉的长期话题,谢谢,我会连的欣赏e只回答我的一个问题:)

+0

Q1 - 您可以使用自动加载按需加载您的类,因此您的第二种调用方法可能是'$ instance-> moduleY-> f4();'。 Q2 - 我认为静态方法将是去那里的方法。 – JohnP 2011-04-13 17:37:20

+0

我想到了这一点,但有时我可能会声明所有模块,但我不希望它们都加载到我的baseClass中。 – 2011-04-13 17:42:38

+0

我回答了更多细节。你不应该加载到你的基类 – JohnP 2011-04-13 17:55:32

回答

3

对于数据库和记录器,我会考虑使用单例模式。

<?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; 
    } 
} 

?> 

一般来说,您可能想看看PHP框架需要PHP5,如Kohana。而且,就模式和PHP而言,您可能希望签出“PHP对象,模式和练习”。

+0

我只会建议使用Singletone作为记录器,因为它是您的调试功能,应该稍后在生产中被禁用... Singletone for Database有一个不好的口味,因为你总是会遇到麻烦,以后再测试你的代码(你应该选择) – chozilla 2015-04-24 11:33:09

1

Q1 - 我会用autoloader function加载类。你可以解析类名来找出你要加载的类的位置和类型(例如 - 控制器,模块,插件等)。

结合__get()(在您的基类中),如果需要,您将能够调用您的模块,如$instance->moduleX->f1();

Q2 - 我也使用这些类型的活动的静态类。除了拥有一个全球可用的变量 - 在其他领域有与您的代码相冲突的风险之外,您无法做其他事情。

Q3 - 有一种类似于你想要达到的东西的模式,但是对于我的生活,我现在似乎无法记住它。但它是如何发生的,你需要在你的主类中注册你的修饰符类。通过查看基类模块数组,或将修饰符类传递给主类(tagCreator),可以了解如何构建应用程序。

但是您决定这么做,您需要修改您的createTag()方法以在返回输出之前查找加载的修饰符类(styleFunctionality)。你的修饰符类当然需要某种标准接口供你的主类调用。

一句警告,看着你如何将你的模块加载到同一个实例中。如果两个类具有相同的方法定义,则可能会产生冲突。我建议你像$this->ModuleA->aMethod()那样分别访问它们。

+0

对于Q3我认为你正在寻找工厂模式? – preinheimer 2011-04-13 18:02:25

+0

@preinheimer nope,不是工厂模式。这对创建对象很有用。让我们看看谷歌带来了什么 – JohnP 2011-04-13 18:03:57

+0

哦,所以很困惑。观察? http://en.wikipedia.org/wiki/Observer_pattern – preinheimer 2011-04-13 18:06:44