7 Stimmen

Strategien zur Verwaltung langer Klassendateien in PHP

Ich habe eine Menge Funktionen, die ich in eine Klasse verschieben möchte. Sie sind derzeit in ein paar ziemlich langen Dateien aufgeteilt. Ich würde lieber keine Datei mit 2500 Zeilen haben, aber soweit ich das beurteilen kann, können Sie `include` nicht verwenden, um eine Klasse in mehrere Dateien aufzuteilen. In der Theorie könnte ich die Funktionen in verschiedenen Klassen gruppieren, aber sie sind eng genug miteinander verbunden, dass ich der Meinung bin, dass sie zusammengehören und die Aufteilung einige der Nützlichkeit reduzieren wird, die ich mir erhoffe, wenn ich mich von einem prozeduralen Ansatz (mit gemeinsamen Eigenschaften anstelle einer Menge von Parametern, die in fast jeder Funktion vorhanden sind) entferne.

Ich weiß, dass dies ein wenig vage ist, aber irgendwelche Vorschläge/Hinweise? Wenn es wichtig ist, dies ist für einen Prototyp, daher hat die einfache Code-Verwaltung Vorrang vor Sicherheit und Leistung.

AKTUALISIERUNG: Lassen Sie mich sehen, ob ich etwas von der Vagheit entfernen kann:

Diese Klasse/Diese Funktionen geben den HTML-Code für ein komplexes Formular aus. Es gibt viele verschiedene Abschnitte und Variationen innerhalb jedes Abschnitts, abhängig von etwa 5 oder 6 Parametern, die derzeit an die Funktionen übergeben werden. Ich hatte gehofft, die Parameter einmal als Eigenschaften der Klasse zu definieren und dann von allen Abschnitt-Erstellungsmethoden aus darauf zuzugreifen. Wenn ich Unter-Klassen verwende, werden die Werte dieser Eigenschaften nicht ordnungsgemäß initialisiert, daher der Wunsch nach einer Klasse (Hmm... es sei denn, ich definiere sie als statisch. Ich habe vielleicht gerade meine eigene Frage beantwortet. Ich muss nachsehen, ob es irgendeinen Grund gibt, warum das nicht funktionieren würde.)

Ich habe derzeit ein Durcheinander von Funktionen wie:

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

Also habe ich mir anfangs etwas wie Folgendes vorgestellt:

class MyForm {
    public $type;          // oder vielleicht wären sie privat
    public $mode;          // ich würde Getter und Setter verwenden
    public $read_only;     // lassen Sie uns davon nicht ablenken :)
    public $values_array;
    // usw.

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

    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() {}
    // usw. für 2500 Zeilen
}

Jetzt denke ich an etwas wie:

// Datei für Container-Klasse
class MyForm {
    static $type 
    static $mode
    static $read_only
    static $values_array
    // usw.

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

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

// Datei für Abschnitt A
class SectionA extends MyForm {
    function __constructor() { 
        if (MyForm::$type == 'foo') { }
        else { }
    }

    function __toString() {
        // Rückgabe der Zeichenfolgen-Repräsentation des Abschnitts
    }
}

// usw.

Oder wahrscheinlich brauche ich eine abstrakte Klasse von FormSection, in der die Eigenschaften vorhanden sind.

Irgendwelche anderen Ideen/Ansätze?

6voto

Peter Bailey Punkte 103278

Ich würde sie in so viele Klassen aufteilen, wie du möchtest (oder so viele, wie sinnvoll sind) und dann einen Autoloader definieren, um Einschlussprobleme zu umgehen.

BEARBEITEN

Ok, nachdem ich mehr von deinem Code gesehen habe - ich denke, du gehst Unterklassen falsch an. Du hast viele if-Anweisungen gegen $type, was mir signalisiert, dass das ist, worauf sich die Polymorphie beziehen sollte.

abstrakte Klasse MyForm
{
  geschützt
      $modus
    , $schreibgeschuetzt
    , $werte
  ;

  public function __construct( $modus, $schreibgeschuetzt=false, array $werte = array() )
  {
    $this->modus           = $modus;
    $this->schreibgeschuetzt = (boolean)$schreibgeschuetzt;
    $this->werte           = $werte;
  }

  abstrakte Funktion get_section_A();

  abstrakte Funktion get_section_B();

  abstrakte Funktion get_section_C();

  //  final nur, wenn du nicht willst, dass Unterklassen überschrieben werden
  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()
  {
    // egal was
  }

  public function get_section_B()
  {
    // egal was
  }

  public function get_section_C()
  {
    // egal was
  }
}

4voto

Alix Axel Punkte 146320

Normalerweise mache ich so etwas:

Klasse eins
{
    public function __get($schlüssel)
    {
        // Datei __DIR__ / $schlüssel . php einbinden
        // Unterklasse instanziieren
    }

    public function hauptmethode()
    {
    }
}

Klasse eins_subEins erstreckt sich über eins
{
    public function andereMethode()
    {
    }
}

Klasse eins_subZwei erstreckt sich über eins
{
    public function eineAndereMethode()
    {
    }
}

$eins->hauptmethode();
$eins->subEins->andereMethode();
$eins->subZwei->eineAndereMethode();

3voto

oops Punkte 5199

Was den Aufbau der Ansicht betrifft, könnten Sie das CompositeView-Muster ausprobieren.

Hier ist ein kleines Beispiel, wie es in PHP aussehen könnte. Tun Sie für dieses Beispiel so, als ob View::$html in einer Template-Klasse encapsulated ist, die HTML vom Laufwerk laden kann und es Ihnen ermöglicht, Variablen einzufügen, Ausgabevermeidung behandelt, usw.

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();
        }   
    }   
}

Der Grund für das IView-Interface ist, dass Sie zusammengesetzte Ansichten mit anderen zusammengesetzten Ansichten erstellen können.

Nehmen wir nun ein Formular mit drei Teilen an: Kopfzeile, Hauptteil und Fußzeile.

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

class BodyView extends View {
    public function __construct() {
        $this->html .= "Hallo zusammen.\n";
    }   
}

class FooterView extends View {
    public function __construct() {
        $this->html .= "© 2012\n";
    }   
}

(Noch einmal, Sie würden nicht einfach HTML in diese öffentliche Variable schreiben und die Ausgabevermeidung selbst behandeln. Sie würden wahrscheinlich einen Vorlagennamen referenzieren und Ihre Daten über das Interface der Vorlage registrieren.)

Dann, um alles zusammenzusetzen, würden Sie folgendermaßen vorgehen:

$view = new CompositeView();
// hier würden Sie Entscheidungen darüber treffen, welche Teile basierend auf Ihrer Geschäftslogik einzuschließen sind.  siehe Hinweis unten.
$view->addPartial(new HeaderView());
$view->addPartial(new BodyView());
$view->addPartial(new FooterView());
$view->display();

Jetzt können Ihre Ansichten zusammengesetzt und die Fragmente wiederverwendet werden, aber Sie können leicht ein Durcheinander mit dem Code machen, der sie aufbaut, besonders wenn Sie viele Bedingungen und viele verschiedene mögliche Ergebnisse haben (was anscheinend der Fall ist). In diesem Fall wird das Strategy-Muster wahrscheinlich von Hilfe sein.

Wenn Sie noch nicht den SOLID-Artikel von UncleBob gelesen haben, tun Sie es, bevor Sie irgendetwas anderes tun! Zumindest das Prinzip der einzigen Verantwortung. Ich empfehle auch, das Buch Refactoring to Patterns von Joshua Kerievsky irgendwann zu lesen.

1voto

Gordon Punkte 304254

Wenn Sie OOP machen möchten, trennen Sie die Anliegen und kapseln sie in geeignete Klassen ein. Kombinieren Sie sie entweder durch Erweiterung oder durch Komposition oder besser Aggregation. Entfernen Sie jeglichen doppelten Code. Wiederholen Sie sich nicht.

In Ihrem Fall trennen Sie die Dinge, die sich auf irgendein Formular beziehen, von den Dingen, die sich auf Ihr spezifisches Formular beziehen. Der Code, der für jedes Formular verwendet werden kann, ist der Code, den Sie in eine generische Formularklasse platzieren möchten. Sie können dies in späteren Projekten wiederverwenden. Ein Beispiel für eine sehr komplexe Formularklasse finden Sie unter Zend_Form.

Alles in Ihrem Code, was mit einem/bestimmten Formular zusammenhängt, gehört in eine eigene Klasse, die das generische Formular erweitert. Anhand der im Code angegebenen Eigenschaft type könnten Sie am Ende mehrere spezielle Formklassen haben (anstelle von einer-eine-Fits-all-Form), was wahrscheinlich die Komplexität der getSection-Methoden beseitigt und Ihren Code viel einfacher zu warten macht, weil Sie sich darauf konzentrieren können, wie ein bestimmter Typ von Formular aussehen und funktionieren soll.

Zu guter Letzt, wenn Sie Code im dort haben, der Daten für das Formular aus dem Formular abruft oder anderweitig nicht direkt mit dem Formularaufbau zusammenhängt, entfernen Sie ihn und erstellen Sie daraus eine separate Klasse. Denken Sie daran, Sie möchten die Anliegen trennen und die Anliegen Ihrer Formularklassen sind es, ein Formular zu erstellen, nicht die Daten abzurufen oder Ähnliches. Daten sind etwas, das Sie dem Formular über den Konstruktor oder einen dedizierten Setter übergeben möchten.

0voto

Tyler Carter Punkte 58971

Sie befinden sich alle in verschiedenen Dateien, was bedeutet, dass sie unterschiedlich genug waren, um nach Datei zu gruppieren. Verwenden Sie einfach dieselbe Logik, wenn Sie sie in Klassen erstellen. Ich habe ein Seitenobjekt, das sich mit dem Aufbau der Seite befasst. Technisch gesehen ist das HTML für meinen Seitenheader Teil der Seite, aber ich trenne es in eine Page_HTML-Klasse, um meine geistige Gesundheit zu bewahren und keine riesigen Klassen zu erstellen.

Zudem neige ich dazu, die Unterklasse, wie Page_HTML in diesem Fall, statisch zu machen, anstatt sie zu instanziieren. Auf diese Weise kann ich auf die $this-Variablen in der Seitenklasse zugreifen, aber sie dennoch in eine andere Klasse gruppieren.

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

class Page_HTML
{
    function getHeader()
    {
    }
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X