web-dev-qa-db-ja.com

PHPの静的クラス初期化子

いくつかの静的関数を持つヘルパークラスがあります。クラス内のすべての関数は、1回実行するために「重い」初期化関数を必要とします(コンストラクターであるかのように)。

これを達成するための良い習慣はありますか?

私が考えた唯一のことは、init関数を呼び出し、それが既に一度実行された場合にそのフローを壊すことでした(静的$initialized var)。問題は、クラスのすべての関数で呼び出す必要があることです。

83
user258626

静的メソッドの束ではなく、シングルトンの方が適切に処理されるように聞こえます

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

そして、使用中

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

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

Foo::init();

この方法では、クラスファイルが含まれているときに初期化が行われます。自動ロードを使用して、これが必要な場合にのみ(そして一度だけ)発生することを確認できます。

93
Victor Nicollet

実際には、初期化が必要な(または少なくともコードを実行する必要がある)静的クラスで、パブリック静的メソッド__init__()を使用します。次に、私のオートローダーでは、クラスをロードするときにis_callable($class, '__init__')をチェックします。存在する場合、そのメソッドを呼び出します。素早く、シンプルで効果的...

55
ircmaxell

init()メソッドを一度呼び出して使用を禁止する方法があります。関数をプライベート初期化子に変更し、クラス宣言の後に次のように呼び出すことができます。

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

注:これは、OPが言ったこととまったく同じです。(ただし、コードは表示しませんでした。)ここで詳細を表示し、受け入れられた回答と比較できるようにします。私のポイントは、OPの最初の本能は、私見であり、彼が受け入れた答えよりも優れていたということです。


受け入れられた答えがどれほど高く支持されているかを考えると、静的メソッドの1回限りの初期化に対する「素朴な」答えは、シングルトンの実装よりも多くのコードではないことを指摘したいと思います-そしてhas本質的な利点

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

このアプローチの利点は、単純な静的関数構文で呼び出すことができることです:

MyClass::someMethod1();

受け入れられた回答で必要な呼び出しとは対照的です。

MyClass::getInstance->someMethod1();

一般的な原則として、クラスをコーディングするときに、呼び出し元をよりシンプルにするために、コーディング価格を一度支払うのが最善です。


すべての回答(これを含む)の中で、私は Victor Nicolletの回答 を好みます。シンプル。追加のコーディングは不要です。理解するための「高度な」コーディングはありません。 (「init」が2回実行されないように、FrancescoMMのコメントを含めることをお勧めします。)

ですから、この答えを書くのは面倒でした。しかし、非常に多くの人々が受け入れられた答えを支持したため、一部の人々は単純な「ナイーブ」なアプローチに気づいていないと結論付けました(ここに示します)。これを出発点として理解してください。

2
ToolmakerSteve

public静的初期化子が気に入らない場合は、リフレクションを回避することができます。

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