PHP

PHP におけるクラス初期化 (static initializer)

クラス初期化方法

Java では次の方法で、

public class MyClass
{
    static
    {
        // クラスの初期化時に実行されるコード
    }
}

C# では次の方法で、

public class MyClass
{
    static MyClass()
    {
        // クラスの初期化時に実行されるコード
    }
}

クラスの初期化時に実行するコードを記述することができる。

しかし、調べた範囲では、PHP の文法にはクラスを初期化する方法が用意されていないようだ。

議論

Stack Overflow に 7 年以上前に投稿された「Static class initializer in PHP」という質問があり、回答が幾つか寄せられている。

シングルトンパターンを使うとよいのでは」という回答が Accepted されているが、これは愚策。クラス初期化コードを記述したいだけなのに、シングルトンパターンにしなければならないというのは馬鹿げている。

public static function __init__() を用意して autoloader でクラスロード時に呼ぶ」という方法も多くの Upvote を集めている。

public static function init() を用意してクラス定義の直後に呼ぶ」という方法は Accept された回答の次に Upvote を集めている。単純で分かりやすい。しかしながら、コメント欄に次のような書き込みがある。

this is ugly. Your code makes init a public method, and it wouldn't work if it's private. Isn't there a cleaner way like the java static class initializer?

確かにクラス初期化メソッドが public なのは望ましくない。しかし、ugly なのはクラス初期化方法を持たない PHP の言語仕様のほうだ

それにしても、PHP が class を導入した際、他言語での先行事例が既にあっただろうに、なぜクラス初期化の方法を仕様として定めなかったのだろうか?

private static メソッドを外部から呼ぶ

初期化メソッドを public ではなくて private にできるのであれば、個人的には、クラス定義直後にクラス初期化メソッドを呼ぶ方法が分かりやすくて良いと思う(autoloader 等に依存したくない)。

PHP 5.3.2 で ReflectionMethod に追加された setAccessible(bool) を使えば、private メソッドでも呼ぶことができる。これを利用すれば、指定したクラスの private static function initialize() を実行する LanguageUtility::initializeClass($class) を次のように定義することができる。

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

クラス初期化実行

上記で定義した LanguageUtility::initializeClass($class) があれば、クラスの初期化は次のように記述することができる。

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

LanguageUtility::initializeClass('MyClass');
// 次のようにも書ける
// LanguageUtility::initializeClass(MyClass::class);

とはいえ、クラス初期化メソッドが public でも気にならないのであれば、Stack Overflow の回答にあったように、単純に次の方法で十分である。

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

MyClass::initialize();

まとめ

  • PHP の文法には、クラス初期化コードを記述する方法は無い。
  • static なクラス初期化メソッドを定義し、自分で呼ぶしかない。
  • クラス定義の直後にクラス初期化メソッドを呼ぶのが、単純で分かりやすい。
  • クラス初期化メソッドを private にしたければ、ReflectionMethod を使う。