如何通过PHP中的一个父类访问多个类

时间:2009-10-13 04:36:58

标签: php oop

假设我有一个名为PageBuilder的类,它实例化,通过我的index文件(充当前端控制器)发送参数和调用函数。有PageBuilder类关联的三个子类:HeadBodyFoot,由PageBuilder访问,基本上将它们抽象为{{1} }}。

所以理论上你可以实例化index并拥有对其他类的完全访问权限,就像它们是PageBuilder的一部分一样。

如何使用类,抽象类和接口的任意组合在PHP5中实现这样的设计?

我不认为PHP5可以实现上述功能,不一定是因为PHP有​​其局限性,但可能是因为我以错误的方式设计我的应用程序。

PHP中OOP的常见示例不足以帮助我理解如何构建更复杂的设计。

感谢。

4 个答案:

答案 0 :(得分:4)

其他一些答案是正确的。您遇到的问题是您的PageBuilder课程做得太多了。对于你正在尝试用它做的事情,这个名字听起来是错误的。 PageBuilder听起来像是将一堆部分组合成Page的东西。我们称这些部分为Section。然后,你想要做的就是使用构图,正如几个答案所暗示的那样。

继承通常被描述为is-a关系,因为如果您的Section类扩展PageBuilder类,则SectionPageBuilder。你想要的是一个has-a关系,就像你的PageBuilder类有一个(或很多)Section(s)一样。任何时候你需要has-a关系,你应该关注组合而不是继承。

所以这可能是你的类层次结构:

abstract class PageBuilder
{
    //@var Section
    public $header;

    //@var Section
    public $body;

    //@var Section
    public $footer;

    public function render()
    {
        echo $this->header.$this->body.$this->footer;
    }
}

class Section
{
    protected $content;
}

class LoginPage
    extends PageBuilder
{
    public function __construct()
    {
        $this->header=new Section(...);
        $this->footer=new Section(...);
        $this->body=new Section(...);
    }
}

在这一点上,你真的是通过制造一个糟糕的MVC系统来重新发明轮子。如果这是一个项目(而不是学习),你应该考虑使用PHP的一个MVC框架。 (我推荐Kohana,但有关于Stack Overflow上最好的PHP版本的several questions。)如果您正在考虑这些事情,MVC可能不会是一个很好的飞跃。

答案 1 :(得分:2)

根据我的理解,你可以使用复合模式

http://en.wikipedia.org/wiki/Composite_pattern

您的控制器索引只能访问实现接口IPageBuilder(或类似名称)的对象,其中一些标准函数类似于“generatePage”。实际上,这个对象是包含IPageBuilder类型的其他对象的某种容器。那些叶子对象将能够构建页面的一些子部分,如头部,身体和脚部。每个叶对象都是不同的类,但它们将实现IPageBuilder接口。当您的索引对象调用“generatePage”时,容器将按顺序调用其每个叶对象的“generatePage”方法,这将依次处理呈现HTML。

使用这种方法,如果您的Body类变得太大,您可以随时将其转换为实现IPageBuilder接口的容器,例如博客帖子Body可以包含Article对象和CommentList对象。然后,body对象只会将“generatePage”方法传播到其子对象。

要创建IPageBuilder对象,可以使用工厂模式

http://en.wikipedia.org/wiki/Factory_method_pattern

说实话,我过去曾尝试过这种方法来生成我的HTML并发现它们有点矫枉过正。我的建议是使用模板引擎,比如Smarty。如果那样做,你的设计师会爱你(或者更少恨你)。

http://www.smarty.net/

如果你想知道如何在PHP中使用接口,那不是很难......

http://ca.php.net/manual/en/language.oop5.interfaces.php

答案 2 :(得分:0)

所以如果我理解正确你想要Head,Body和Foot自动构建为PageBuilder的孩子吗?

有几种方法可以做到这一点。

1)在PageBuilder中创建变量以保存类并使用__call方法

class PageBuilder{
   private _head;
   private _body;
   private _foot;

   function __construct(){
       $this->_head = new Head();
       $this->_foot = new Foot();
       $this->_body = new Body();
   }

   function __call($name, $args){
       if(method_exists($this->_head, $name)) call_user_func_array(array($this->head, $name), $args);

       // Repeat for other classes.

   }

}

这里的问题显然是,如果两个类共享相同的方法,那么第一个出现的方法获胜。您可以修改它以便很容易地根据函数名称选择一个类。

2)将一切都束缚下来。

Abstract class Page{
}

class Head extends Page{
}

class Body extends Head{
}

class Foot extends Body{
}

class PageBuilder extends Foot{
}
无论哪种方式都有点被黑,你只需要让它发挥作用。

答案 3 :(得分:-1)

PHP只允许您扩展一个父类(它可以反过来扩展另一个父类等)。没有接口,这意味着你不能像在C ++中那样从多个接口继承函数或属性。

因此,你可能需要做更多这样的事情:

class PageBuilder {
    protected Head, Body, Foot;

    public function __construct($request) {
        $view = $this->getView($request);

        $this->Head = new PageSection('head.tpl');
        $this->Body = new PageSection($view);
        $this->Foot = new PageSection('foot.tpl');
    }

    private function getView($request) {
        // @todo return the template filename/path based upon the request URL
    }
}

class PageSection {
    private $template;

    public function __construct($template) {
        $this->template = $template;
    }

    public function render() {
        // @todo process and output the $this->template file
    }
}