it-swarm.com.de

Statischer Klasseninitialisierer in PHP

Ich habe eine Hilfsklasse mit einigen statischen Funktionen. Alle Funktionen in der Klasse erfordern eine einmalige Initialisierungsfunktion (wie bei einem Konstruktor).

Gibt es eine gute Praxis, um dies zu erreichen?

Das einzige, woran ich dachte, war das Aufrufen einer init-Funktion und das Unterbrechen des Flusses, wenn sie bereits einmal ausgeführt wurde (mit einem statischen $initialized var). Das Problem ist, dass ich es für jede Klasse der Klasse aufrufen muss.

79
user258626

Klingt, als wären Sie mit einem Singleton besser bedient als mit einer Reihe statischer Methoden

class Singleton
{
  /**
   * 
   * @var Singleton
   */
  private static $instance;

  private function __construct()
  {
    // Your "heavy" initialization stuff here
  }

  public static function getInstance()
  {
    if ( is_null( self::$instance ) )
    {
      self::$instance = new self();
    }
    return self::$instance;
  }

  public function someMethod1()
  {
    // whatever
  }

  public function someMethod2()
  {
    // whatever
  }
}

Und dann im Gebrauch

// As opposed to this
Singleton::someMethod1();

// You'd do this
Singleton::getInstance()->someMethod1();
104
Peter Bailey
// file Foo.php
class Foo
{
  static function init() { /* ... */ }
}

Foo::init();

Auf diese Weise erfolgt die Initialisierung, wenn die Klassendatei enthalten ist. Sie können sicherstellen, dass dies nur bei Bedarf (und nur einmal) geschieht, indem Sie das automatische Laden verwenden. 

90
Victor Nicollet

Eigentlich verwende ich eine öffentliche statische Methode __init__() für meine statischen Klassen, für die eine Initialisierung erforderlich ist (oder zumindest Code ausführen muss). Wenn er dann in meinem Autoloader eine Klasse lädt, prüft er is_callable($class, '__init__'). Wenn ja, ruft es diese Methode auf. Schnell, einfach und effektiv ...

53
ircmaxell

Es gibt eine Möglichkeit, die init()-Methode einmal aufzurufen und deren Verwendung zu verbieten. Sie können die Funktion in einen privaten Initialisierer umwandeln und sie nach der Klassendeklaration folgendermaßen aufheben:

class Example {
    private function init() {
        // do whatever needed for class initialization
    }
}
(function () {
    static::init();
})->bindTo(null, Example::class)();
2
brzuchal

HINWEIS: Dies ist genau das, was OP gesagt hat. (Zeigt aber keinen Code für.) Ich zeige die Details hier, damit Sie sie mit der akzeptierten Antwort vergleichen können. Mein Punkt ist, dass OPs ursprünglicher Instinkt meiner Meinung nach besser war als die Antwort, die er akzeptierte.


Angesichts der hohen Resonanz der akzeptierten Antwort möchte ich auf die "naive" Antwort zur einmaligen Initialisierung statischer Methoden hinweisen, die kaum mehr Code enthält als die Implementierung von Singleton - und einen wesentlichen Vorteil hat .

final class MyClass  {
    public static function someMethod1() {
        MyClass::init();
        // whatever
    }

    public static function someMethod1() {
        MyClass::init();
        // whatever
    }


    private static $didInit = false;

    private static function init() {
        if (!$didInit) {
            $didInit = true;
            // one-time init code.
        }
    }

    // private, so can't create an instance.
    private function __construct() {
        // Nothing to do - there are no instances.
    }
}

Der Vorteil dieses Ansatzes ist, dass Sie mit der einfachen statischen Funktionssyntax aufrufen können:

MyClass::someMethod1();

Vergleichen Sie es mit den Anrufen, die für die angenommene Antwort erforderlich sind:

MyClass::getInstance->someMethod1();

Im Allgemeinen ist es am besten, den Codierungspreis einmal zu zahlen, wenn Sie eine Klasse codieren, um den Aufrufer einfacher zu halten.


Von allen Antworten (einschließlich dieser) bevorzuge ich Victor Nicollets Antwort . Einfach. Keine zusätzliche Codierung erforderlich. Keine "fortgeschrittene" Codierung zu verstehen. (Ich empfehle, FrancescoMMs Kommentar einzuschließen, um sicherzustellen, dass "init" niemals zweimal ausgeführt wird.)

Ich hätte mir also nicht die Mühe machen können, diese Antwort zu schreiben. Aber so viele Leute stimmten der akzeptierten Antwort zu, dass ich schlussfolgere, dass einige Leute sich des offensichtlichen, "naiven" Ansatzes (den ich hier zeige) einfach nicht bewusst sind. Verstehen Sie dies als Ausgangspunkt.

0
ToolmakerSteve

Wenn Sie den statischen Initialisierer public nicht mögen, kann Reflektion eine Problemumgehung sein.

<?php

class LanguageUtility
{
    public static function initializeClass($class)
    {
        try
        {
            // Get a static method named 'initialize'. If not found,
            // ReflectionMethod() will throw a ReflectionException.
            $ref = new \ReflectionMethod($class, 'initialize');

            // The 'initialize' method is probably 'private'.
            // Make it accessible before calling 'invoke'.
            // Note that 'setAccessible' is not available
            // before PHP version 5.3.2.
            $ref->setAccessible(true);

            // Execute the 'initialize' method.
            $ref->invoke(null);
        }   
        catch (Exception $e)
        {
        }
    }
}

class MyClass
{
    private static function initialize()
    {
    }
}

LanguageUtility::initializeClass('MyClass');

?>
0