стратегии для управления файлами длинных классов в php - PullRequest
7 голосов
/ 17 декабря 2009

У меня есть куча функций, которые я хочу перенести в класс. В настоящее время они разбиты на пару довольно длинных файлов. Я бы предпочел не иметь один 2500-строчный файл, но, насколько я могу судить, вы не можете использовать include, чтобы разбить класс на несколько файлов. Теоретически, я мог бы сгруппировать функции по разным классам, но они достаточно тесно связаны, так что я чувствую, что они принадлежат друг другу, и их разделение уменьшит некоторую полезность, которую я надеюсь получить от отказа от процедурного подхода. (с общими свойствами, а не с набором параметров, которые есть почти в каждой функции).

Я знаю, что это немного расплывчато, но какие-нибудь предложения / указатели? Если это имеет значение, то это для прототипа, поэтому простота управления кодом имеет приоритет над безопасностью и производительностью.

ОБНОВЛЕНИЕ : Дайте мне посмотреть, смогу ли я убрать некоторую неопределенность:

Этот класс / набор функций выводит html для сложной формы. В каждом разделе есть много различных разделов и вариантов, в зависимости от примерно 5 или 6 параметров, которые в настоящее время передаются в функции. Я надеялся определить параметры один раз как свойства класса, а затем получить доступ к ним из всех методов создания раздела. Если я использую подклассы, значения этих свойств не будут инициализированы должным образом, отсюда и желание одного класса. (Хм ... если я не определю их как статические. Возможно, я только что ответил на свой вопрос. Мне нужно посмотреть, есть ли причина, которая не сработает.)

В настоящее время у меня беспорядок функций, таких как:

get_section_A ($type='foo', $mode='bar', $read_only=false, $values_array=array()) {
    if ($this->type == 'foo') { }
    else ($this->type == 'foo') { }
}    

Итак, я изначально представлял что-то вроде:

class MyForm {
    public $type;          // or maybe they'd be private or 
    public $mode;          // I'd use getters and setters 
    public $read_only;     // let's not get distracted by that :)
    public $values_array;
    // etc.

    function __constructor ($type='foo', $mode='bar', $read_only=false, $values_array=array()) {
        $this->type = $type;
        // etc.
    }

    function get_sections () {
        $result = $this->get_section_A();
        $result .= $this->get_section_B();
        $result .= $this->get_section_C();        
    }      

    function get_section_A() { 
        if ($this->type == 'foo') { }
        else { }
    }
    function get_section_B() {}
    function get_section_C() {}
    // etc. for 2500 lines
}

Теперь я думаю что-то вроде:

// container class file
class MyForm {
    static $type 
    static $mode
    static $read_only
    static $values_array
    // etc.

    function __constructor ($type='foo', $mode='bar', $read_only=false, $values_array=array()) {
        MyForm::$type = $type;
        // etc.
    }

    function get_sections () {
        $result = new SectionA();
        $result .= new SectionB();
        $result .= new SectionC();
    }      
}

// section A file
class SectionA extends MyForm {
    function __constructor() { 
        if (MyForm::$type == 'foo') { }
        else { }
    }

    function __toString() {
        // return string representation of section
    }
}

// etc.

Или, возможно, мне нужен абстрактный класс FormSection, где живут свойства.

Какие-нибудь другие идеи / подходы?

Ответы [ 6 ]

6 голосов
/ 17 декабря 2009

Я бы разделил их на столько классов, сколько вы хотите (или столько, которые имеют смысл), а затем определил автозагрузчик , чтобы устранить головные боли при включении.

EDIT

Хорошо, увидев больше вашего кода - я думаю, что вы неправильно подходите к подклассам. У вас есть множество if заявлений против $type, что сигнализирует мне, что , что - это то, на чем должен основываться полиморфизм.

abstract class MyForm
{
  protected
      $mode
    , $read_only
    , $values
  ;

  public function __construct( $mode, $read_only=false, array $values = array() )
  {
    $this->mode      = $mode;
    $this->read_only = (boolean)$read_only;
    $this->values    = $values;
  }

  abstract function get_section_A();

  abstract function get_section_B();

  abstract function get_section_C();

  //  final only if you don't want subclasses to override
  final public function get_sections()
  {
    return $this->get_section_A()
         . $this->get_section_B()
         . $this->get_section_C()
    ;
  }
}

class FooForm extends MyForm
{
  public function get_section_A()
  {
    // whatever
  }

  public function get_section_B()
  {
    // whatever
  }

  public function get_section_C()
  {
    // whatever
  }
}
4 голосов
/ 17 декабря 2009

Обычно я делаю что-то вроде этого:

class one
{
    public function __get($key)
    {
        // require __DIR__ / $key . php
        // instanciate the sub class
    }

    public function mainMethod()
    {
    }
}

class one_subOne extends one
{
    public function otherMethod()
    {
    }
}

class one_subTwo extends one
{
    public function anotherMethod()
    {
    }
}

$one->mainMethod();
$one->subOne->otherMethod();
$one->subTwo->anotherMethod();
3 голосов
/ 18 декабря 2009

Что касается построения представления, вы можете попробовать шаблон CompositeView .

Вот небольшой пример того, как это может выглядеть в PHP. Для этого примера представьте, что View::$html инкапсулирован в класс Template, который может загружать html с диска и позволяет вводить переменные, обрабатывать экранирование и т. Д.

interface IView {
    public function display();
}

class View implements IView {
    public $html = ''; 

    public function display() {
        echo $this->html;
    }   
}

class CompositeView implements IView {
    private $views;
    public function addPartial(IView $view) {
        $this->views[] = $view;
    }   
    public function display() {
        foreach ($this->views as $view) {
            $view->display();
        }   
    }   
}

Причиной использования интерфейса IView является возможность создания составных представлений с другими составными представлениями.

Итак, рассмотрим форму с тремя частями: заголовок, тело и нижний колонтитул.

class HeaderView extends View {
    public function __construct() {
        $this->html .= "<h1>Hi</h1>\n";
    }   
}

class BodyView extends View {
    public function __construct() {
        $this->html .= "<p>Hi there.</p>\n";
    }   
}

class FooterView extends View {
    public function __construct() {
        $this->html .= "<h3>&copy; 2012</h3>\n";
    }   
}

(Опять же, вы бы не просто записали HTML в эту общедоступную переменную и обрабатывали бы выход, выходящий из себя. Вероятно, вы бы ссылались на имя файла шаблона и регистрировали свои данные через интерфейс шаблона.)

Тогда, чтобы сложить все вместе, вы бы пошли:

$view = new CompositeView();
// here you would make decisions about which pieces to include, based
// on your business logic.  see note below.
$view->addPartial(new HeaderView());
$view->addPartial(new BodyView());
$view->addPartial(new FooterView());
$view->display();

Так что теперь ваши представления могут быть скомпонованы, а фрагменты использованы повторно, но вы можете легко запутаться в коде, который их строит, особенно если у вас много условий и много разных возможных результатов (что звучит так, как вы делаете). ) В этом случае шаблон Стратегии, вероятно, поможет вам.

Если вы еще не прочитали СОЛНЕЧНУЮ статью UncleBob , сделайте это прежде всего! По крайней мере, принцип единой ответственности. Я также рекомендовал бы в какой-то момент прочесть «Рефакторинг для паттернов» Джошуа Кериевского.

1 голос
/ 17 декабря 2009

Если вы хотите сделать ООП, разделите задачи и инкапсулируйте их в соответствующие классы. Объедините их, расширяя их, или составом или лучшей агрегацией. Удалите любой дублирующий код. Не повторяйся.

В вашем случае отделите материал, который имеет отношение к любой форме, от материала, который относится к вашей определенной форме. Код, который можно использовать для любой формы, - это код, который вы хотите поместить в общий класс Form. Вы можете использовать это в более поздних проектах. Для примера очень сложного класса Form, посмотрите Zend_Form .

Все в вашем коде, связанное с / определенной формой, попадает в собственный класс, расширяющий общую форму. Исходя из свойства type, указанного в вашем коде, вы можете получить несколько классов форм специального назначения (вместо одного типа для всех типов), что, вероятно, устранит сложность методов getSection и сделает Ваш код гораздо проще поддерживать, потому что вы можете сосредоточиться на том, как должен выглядеть и делать конкретный тип формы.

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

0 голосов
/ 17 декабря 2009

Этот класс / набор функций выводит HTML для сложной формы.

Почему бы не удалить PHP из уравнения? Кажется, вы используете PHP для организации представлений, что можно легко сделать с помощью файловой системы. Просто напишите представления в HTML, используя как можно меньше PHP. Затем используйте PHP для сопоставления запросов с представлениями. Я предполагаю, что вы обрабатываете формы с помощью PHP, и вы могли бы продолжать это делать. Тем не менее, ваши классы станут намного меньше, потому что они только принимают, проверяют и предположительно сохраняют ввод.

0 голосов
/ 17 декабря 2009

Все они находятся в разных файлах, что означает, что они были достаточно разными для группировки по файлу. Просто используйте ту же логику при построении их в классы. У меня есть объект Page, который занимается созданием страницы. Технически HTML-код для моего заголовка страницы является частью страницы, но я разделяю его на класс Page_HTML для поддержания своего здравомыслия и не создания гигантских классов.

Кроме того, я склонен делать подклассы, например, Page_HTML в данном случае, статическими, а не создавать их экземпляры. Таким образом, я могу получить доступ к переменным $ this в классе Page, но все же сгруппировать его в другой класс.

class Page
{
    function buildPage($content)
    {
        $content = Page_HTML::getHeader() . $content;
    }
}

class Page_HTML
{
    function getHeader()
    {
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...