2010-02-27 6 views
5

Ich arbeite an einer Klasse, die über statische Funktionsaufrufe sowie Objektmethoden zugänglich sein muss. Eine Sache, die ich gefunden habe, ist, dass ich Logik über mehrere Funktionen vervielfältige.

Vereinfachtes Beispiel:

class Configurable{ 

    protected $configurations = array(); 

    protected static $static_configurations = array(); 

    public function configure($name, $value){ 

     // ...lots of validation logic... 

     $this->configurations[$name] = $value; 

     } 

    public static function static_configure($name, $value){ 

     // ...lots of validation logic (repeated)... 

     self::$static_configurations[$name] = $value; 

     } 

    } 

Ich habe eine Lösung für dieses Problem gefunden, aber es fühlt sich wirklich schmutzig:

class Configurable{ 

    protected $configurations = array(); 

    protected static $static_configurations = array(); 

    public function configure($name, $value){ 

     // ...lots of validation logic... 

     if (isset($this)){ 
      $this->configurations[$name] = $value; 
      } 
     else{ 
      self::$static_configurations[$name] = $value; 
      } 

     } 

    } 

ich die statische Funktion als auch brauchen, so dass ich Konfigurationen festlegen kann überall die Anwendung. Das Schöne an dieser Technik ist auch, dass ich dieselben Methodennamen in beiden Bereichen verwenden kann.

Gibt es irgendwelche Probleme mit dem Testbereich wie diesem? Performance-Probleme, Vorwärtskompatibilitätsprobleme, usw. Es funktioniert alles auf PHP 5.2, und ich muss nicht unterstützen < 5.

Antwort

2

Das Problem mit der zweiten Methode ist, dass es zu einem Fehler bei der Fehlerberichterstattung führen wird ist auf E_STRICT eingestellt. Zum Beispiel:

strenge Maßstäbe: Nicht-statische Methode Foo :: bar() sollte nicht statisch in /home/yacoby/dev/php/test.php on line 10

A genannt werden Punkt mit PHP6 ist, dass die E_STRICT-Fehler nach E_ALL verschoben werden. Mit anderen Worten, E_ALL deckt alle Fehler ab, einschließlich der Möglichkeit, statische Methoden nicht statisch aufzurufen.

Eine alternative Methode könnte darin bestehen, die Validierungslogik in eine statische Funktion zu verschieben. Auf diese Weise können die nicht statische Funktion und die statische Funktion die Validierungslogik aufrufen.

+1

OK, außer dem strengen Fehler gibt es irgendwelche Probleme mit der zweiten Methode? Ich werde es wahrscheinlich auf Ihren Rat hin ändern, aber ich würde gerne die wirklichen Probleme mit Code wie diesem verstehen. Ist es eine Funktion, die wahrscheinlich aus zukünftigen PHP-Versionen entfernt wird, oder können Sie nicht statische Methoden immer statisch aufrufen? – Rowan

+1

'E_STRICT' Fehler tendieren dazu zu sein "Das scheint eine wirklich schlechte Idee zu sein, aber wir werden es trotzdem versuchen lassen." Es gibt keine Garantie, dass so etwas immer funktioniert, aber sie werden wahrscheinlich in "E_NOTICE" oder "E_WARN" konvertiert, bevor sie komplett veraltet sind. – MightyE

+0

Danke für die Klärung, dass @MightyE – Rowan

2

Statische Methoden erfordern eine andere Anzahl von Argumenten als ihr objektives Gegenstück - das zusätzliche Argument wäre ein Ausführungskontext. Wenn es keinen Ausführungskontext gibt, dann macht es nur Sinn, es statisch zu nennen.

Meine bevorzugte Vorgehensweise, da ich eine Bibliothek mit mehreren Schnittstellen wie diesem erstelle, besteht darin, eine statische Klasse und eine dynamische Klasse zu erstellen. Haben Sie einen Proxy die Anrufe an den anderen. Zum Beispiel:

class DynamicClass { 
    protected $foo; 
    protected $bar; 
    public function baz($arg1) { 
     return StaticClass::bar($this->foo, $arg1); 
    } 
    public function zop($arg1, $arg2) { 
     return StaticClass::zop($this->foo, $this->bar, $arg1, $arg2); 
    } 
    // Context-less helper function 
    public function womp($arg1) { 
     return StaticClass::womp($arg1); 
    } 
} 

class StaticClass { 
    public static function baz(&$fooContext, $arg1) { ... } 
    public static function zop(&$fooContext, &$barContext, $arg1, $arg2) { ... } 
    public static function womp($arg1) { ... } 
} 

Es liegt an Ihnen genau, wie Sie Zusammenhang mit dem statischen Klasse übergeben - was Sie tun müssen, was auch immer für Sie Sinn macht. Die Arbeit, die in den meisten Funktionen ausgeführt wird, sollte ziemlich geringfügig sein (wenn Sie viel tun, dann sollten Sie die Arbeit wahrscheinlich in der Regel in kleinere Funktionen aufteilen) und sollten daher nur eine Handvoll von Kontextargumenten benötigen. Oder Sie könnten einen vollständigen Kontext Array erstellen und dass passieren überall herum (entweder in DynamicClass bevölkert nur vor jedem Anruf, oder auch alle DynamicClass Eigenschaften in diesem Array verfolgen, so können Sie schnell & es leicht um passieren.


Obwohl es tatsächlich scheint, dass Sie von einem Singleton Design-Muster profitieren könnten.Was ich sehen kann, versuchen Sie, eine globale Configurable zu erstellen, und haben auch die Möglichkeit, individuelle lokale Configurable s zu erstellen.Mit dem Singleton-Design-Muster erstellen Sie eine global zugängliche Version einer Klasse, von der Sie garantieren können, dass Sie nur eine davon haben (ohne OOP-Designprinzipien zu brechen und sich auf $ _GLOBALS usw. zu verlassen).Zum Beispiel:

class DynamicClass { 
    protected $foo; 
    protected $bar; 

    public function baz($arg1) { ... } 
    public function zop($arg1, $arg2) { ... } 

    public static function getSingleton() { 
     static $instance = null; 
     if ($instance === null) $instance = new DynamicClass(); 
     return $instance; 
    } 
} 

Egal, wo in Ihrem Code Sie sind, können Sie den Zugriff auf die gleiche Instanz mit DynamicClass::getSingleton() zu bekommen. Sie haben auch die Möglichkeit, einmalige Nicht-Singleton-Versionen zu erstellen. Sie erhalten im Wesentlichen das Beste aus beiden Welten, während Sie ausschließlich alle Ihre Methoden mit dynamischem Zugriff berücksichtigen müssen.

2

Ich finde es nicht so absurd, eine Methode auf einer Instanz und auch statisch aufrufen zu dürfen. Mein Fall:

TestRecord::generateForm(); // Generate an empty form. 

    $test = new TestRecord($primaryKey); 
    [...] 
    $test->generateForm();  // Generate an edit form with actual $test values. 

Statische Seite meiner Klasse beschäftigt sich mit blank/neue Logiken, während Instanz Seite bedeutet Live-Daten verwendet werden.

PHP 5.3 ermöglicht dies zu erreichen, indem __call Verwendung __callStatic und static:::

public function __call($name, $args) 
{ 
    if ($name == 'generateForm') { 
    $this->fields = static::createFields(); // Action 1 : static. 
    $this->fillFields();      // Action 2 : instance. 
    static::renderForm($this->fields);  // Action 3 : static. 
    } 
} 

public static function __callStatic($name, $args) 
{ 
    if ($name == 'generateForm') { 
    $fields = static::createFields();  // Action 1 : static. 
              // Action 2 : none. 
    static::renderForm($fields);   // Action 3 : static. 
    } 
} 

Hinweis: Der static:: späte Bindung Qualifier verwendet, weil meine drei Aktionsmethoden (createFields, fillFields und rendreForm) implementiert als protected in den Unterklassen dieser, die abstract ist. Dies ist möglich, weil PHP geschützte Elemente in beiden Richtungen zugänglich macht: von der Basis zur Unterklasse, aber auch von der Unterklasse zur Oberklasse. Was unterscheidet mich von anderen OO-Sprachen, soweit ich weiß.

-1

wie in core php verwenden wir index.php?var=, so das gleiche in oop php zu tun, was wir verwenden sollten.