Как получить доступ к нескольким классам через один родительский класс в PHP - PullRequest
2 голосов
/ 13 октября 2009

Допустим, у меня есть класс с именем PageBuilder, который я создаю, отправляю параметры и вызываю функции из моего файла index (который действует как фронт-контроллер). С классом PageBuilder связаны три подкласса: Head, Body и Foot, к которым обращается PageBuilder, которые в основном абстрагируют их для index.

Таким образом, теоретически вы можете создать экземпляр PageBuilder и иметь полный доступ к другим классам, как если бы они были частью PageBuilder.

Как я могу реализовать такой дизайн в PHP5, используя любую комбинацию классов, абстрактных классов и интерфейсов?

Я не думаю, что вышеупомянутое возможно с PHP5, не обязательно, потому что у PHP есть свои ограничения, но, возможно, потому, что я неправильно оцениваю дизайн своего приложения.

Типичных примеров ООП в PHP недостаточно, чтобы помочь мне понять, как структурировать более сложный дизайн.

Спасибо.

Ответы [ 4 ]

4 голосов
/ 13 октября 2009

Некоторые другие ответы находятся на правильном пути. Проблема, с которой вы сталкиваетесь, заключается в том, что ваш PageBuilder класс делает слишком много. Просто название звучит неправильно для того, что вы пытаетесь с ним сделать. PageBuilder звучит как нечто, что собрало бы кучу частей в Page. Давайте назовем эти части Section. Затем, что вы хотите сделать, это использовать композицию, на что намекали несколько ответов.

Наследование часто описывается как отношение is-a, например, если ваши Section классы расширяют класс PageBuilder, тогда Section будет PageBuilder. Тем не менее, вы хотите иметь 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 . Если это для проекта (а не для обучения), вам следует рассмотреть возможность использования одной из сред MVC для PHP. (Я рекомендую Kohana , но есть несколько вопросов относительно лучших версий PHP на Stack Overflow.) Если вы думаете о подобных вещах, MVC, вероятно, не будет большой скачок для вас.

2 голосов
/ 13 октября 2009

Из того, что я понимаю здесь, вы можете использовать составной шаблон

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

0 голосов
/ 13 октября 2009

Так что, если я правильно понимаю, вы хотите, чтобы голова, тело и нога автоматически создавались как дети 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{
}

В любом случае, он несколько взломан, просто нужно заставить его работать.

0 голосов
/ 13 октября 2009

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
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...