web-dev-qa-db-fra.com

Initialiseur de classe statique dans PHP

J'ai une classe d'assistance avec des fonctions statiques. Toutes les fonctions de la classe nécessitent une fonction d’initialisation "lourde" à exécuter une fois (comme si c’était un constructeur).

Existe-t-il une bonne pratique pour y parvenir?

La seule chose à laquelle je pensais était d’appeler une fonction init et d’interrompre son flux si elle s’était déjà exécutée une fois (avec un $initialized var statique). Le problème est que je dois faire appel à chacune des fonctions de la classe.

79
user258626

On dirait que vous seriez mieux servi par un singleton que par un tas de méthodes statiques

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
  }
}

Et puis, en usage

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

De cette façon, l'initialisation se produit lorsque le fichier de classe est inclus. Vous pouvez vous assurer que cela ne se produit que lorsque cela est nécessaire (et une seule fois) en utilisant le chargement automatique. 

90
Victor Nicollet

En fait, j'utilise une méthode statique publique __init__() sur mes classes statiques qui nécessitent une initialisation (ou au moins une exécution de code). Ensuite, dans mon autochargeur, lorsqu'il charge une classe, il vérifie is_callable($class, '__init__'). Si c'est le cas, il appelle cette méthode. Rapide, simple et efficace ...

53
ircmaxell

Il existe un moyen d'appeler la méthode init() une fois et d'interdire son utilisation. Vous pouvez transformer la fonction en initialiseur privé et l'ivoler après la déclaration de classe comme ceci:

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

NOTE: C’est exactement ce que OP a dit avoir fait. (mais n'a pas montré de code pour.) J'indique les détails ici, afin que vous puissiez le comparer à la réponse acceptée. Mon point est que l'instinct initial de OP était, à mon humble avis, meilleur que la réponse qu'il a acceptée.


Compte tenu de la grande popularité de la réponse acceptée, j'aimerais souligner que la réponse "naïve" à l'initialisation ponctuelle de méthodes statiques est à peine plus de code que la mise en oeuvre de Singleton - et présente un avantage essentiel .

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.
    }
}

L'avantage de cette approche, est que vous pouvez appeler avec la syntaxe de la fonction statique la plus simple:

MyClass::someMethod1();

Comparez-le aux appels requis par la réponse acceptée:

MyClass::getInstance->someMethod1();

En règle générale, il est préférable de payer une fois le prix de codage, lorsque vous codez une classe, pour simplifier la tâche des appelants.


Parmi toutes les réponses (y compris celle-ci), je préfère la réponse de Victor Nicollet . Simple. Aucun codage supplémentaire requis. Pas de codage "avancé" à comprendre. (Je recommande d'inclure le commentaire de FrancescoMM pour s'assurer que "init" ne s'exécutera jamais deux fois.)

Je n'aurais donc pas pu prendre la peine d'écrire cette réponse. Mais beaucoup de gens ont voté en faveur de la réponse acceptée, ce qui, j'en conclus, est simplement ignoré de l'approche évidente "naïve" (que je montre ici). Comprenez cela comme un point de départ.

0
ToolmakerSteve

Si vous n'aimez pas public initialiseur statique, la réflexion peut constituer une solution de contournement.

<?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
Takahiko Kawasaki