PHPで(C#のように)静的クラスを作成することは可能ですか?


139

PHPで静的クラスを作成し、C#と同じように動作させたいので、

  1. クラスへの最初の呼び出しでコンストラクターが自動的に呼び出されます
  2. インスタンス化は不要

このようなもの...

static class Hello {
    private static $greeting = 'Hello';

    private __construct() {
        $greeting .= ' There!';
    }

    public static greet(){
        echo $greeting;
    }
}

Hello::greet(); // Hello There!

静的クラスがどのように振る舞うべきかを簡単に説明できますか?ユーティリティの実装ですか?
xtofl 2009年

私の意見を投げ捨てるだけですが、PHPでの経験から、健全性、テスト容易性、およびスケーラビリティのために、静的クラスはほとんど完全にステートレスであり、オブジェクト指向のものよりも機能的なプログラミングのようなAPIを提供する必要があります。完全にインスタンス化されたオブジェクトのアクセシビリティファサードとして、またはヘルパーまたは類似のコンストラクトのユーティリティラッパーとして使用する場合は、それらを使用する場合に最適です。
モプシッド2017年

回答:


200

PHPで静的クラスを持つことはできますが、それらは自動的にコンストラクターを呼び出しません(呼び出してみた場合self::__construct()、エラーが発生します)。

したがって、initialize()関数を作成し、各メソッドで呼び出す必要があります。

<?php

class Hello
{
    private static $greeting = 'Hello';
    private static $initialized = false;

    private static function initialize()
    {
        if (self::$initialized)
            return;

        self::$greeting .= ' There!';
        self::$initialized = true;
    }

    public static function greet()
    {
        self::initialize();
        echo self::$greeting;
    }
}

Hello::greet(); // Hello There!


?>

20
私は、関数をすべて1か所にまとめるために、これを頻繁に行っています。IEユーティリティ:: doSomethingUseful();
smack0007 2009年

16
代わりに、パブリック関数Therefore you'd have to create an initialize() function and call it in each method:を作成しinitializeて、クラスの宣言の直後に呼び出す方が簡単です。
chacham15

4
私はこれがかなり古いことを知っていますが、今では魔法の__callStaticを使用できるので、静的メソッドなどを呼び出すと__callStatic、最初にが呼び出され、そこで初期化されているself::$methodかどうかを確認してから、何を呼び出しているかを確認できます。それでもメソッドを直接呼び出している場合は、すべてをプライベートに変更してみてください。
matiaslauriti 2017年

1
2つのスレッドが同時に挨拶するとどうなりますか?同期がないため、初期化が2回呼び出されることはありません(この場合は問題ありませんが、他の多くの場合はそうではありません)。または、phpはシングルスレッドで非プリエンプティブのようなノードですか?
John Little、

53

グレッグの答えに加えて、コンストラクターをプライベートに設定して、クラスをインスタンス化できないようにすることをお勧めします。

だから私の控えめな意見では、これはグレッグの例に基づいたより完全な例です:

<?php

class Hello
{
    /**
     * Construct won't be called inside this class and is uncallable from
     * the outside. This prevents instantiating this class.
     * This is by purpose, because we want a static class.
     */
    private function __construct() {}
    private static $greeting = 'Hello';
    private static $initialized = false;

    private static function initialize()
    {
        if (self::$initialized)
            return;

        self::$greeting .= ' There!';
        self::$initialized = true;
    }

    public static function greet()
    {
        self::initialize();
        echo self::$greeting;
    }
}

Hello::greet(); // Hello There!


?>

1
これは素晴らしいアプローチです。ただし、singeltonがパブリックコンストラクターを必要とする特定のオブジェクトから継承する場合、構成関数は実装できません。
Eric Herlitz

4
@EricHerlitzこの質問はシングルトンに関するものではなく、静的クラスに関するものです。インスタンス化することを意図したクラスから継承する静的クラスを作成したいのはなぜですか?
マークアメリー2014年

3
同様にクラスを抽象として宣言し、インスタンス化されないようにし、静的メソッドの呼び出しを許可します。
bstoney

24

あなたはそれらの「静的」のようなクラスを持つことができます。しかし、私は本当に重要な何かが欠けていると思います:phpにはアプリサイクルがないため、アプリケーション全体で実際の静的(またはシングルトン)を取得できません...

PHPのシングルトンを参照


1
静的クラスとシングルトンは2つの異なるものです。
Max Cuttins

4
final Class B{

    static $staticVar;
    static function getA(){
        self::$staticVar = New A;
    }
}

bの構造はsingetonハンドラーと呼ばれ、aでも実行できます

Class a{
    static $instance;
    static function getA(...){
        if(!isset(self::$staticVar)){
            self::$staticVar = New A(...);
        }
        return self::$staticVar;
    }
}

これはシングルトンの使用です $a = a::getA(...);


3

私は通常、通常の非静的クラスを記述し、ファクトリクラスを使用してオブジェクトの単一の(sudo static)インスタンスをインスタンス化することを好みます。

このように、コンストラクタとデストラクタは通常どおりに機能し、必要に応じて追加の非静的インスタンスを作成できます(たとえば、2番目のDB接続)。

私はこれを常に使用しており、ページが終了するとデストラクタがセッションをデータベースにプッシュするため、カスタムDBストアセッションハンドラを作成するのに特に役立ちます。

もう1つの利点は、すべてがオンデマンドでセットアップされるため、呼び出す順序を無視できることです。

class Factory {
    static function &getDB ($construct_params = null)
    {
        static $instance;
        if( ! is_object($instance) )
        {
            include_once("clsDB.php");
            $instance = new clsDB($construct_params);   // constructor will be called
        }
        return $instance;
    }
}

DBクラス...

class clsDB {

    $regular_public_variables = "whatever";

    function __construct($construct_params) {...}
    function __destruct() {...}

    function getvar() { return $this->regular_public_variables; }
}

どこでも使いたいだけ電話をかけて...

$static_instance = &Factory::getDB($somekickoff);

次に、すべてのメソッドを静的ではないものとして扱います(それらが静的であるため)

echo $static_instance->getvar();

1
これは実際にはシングルトンパターンの実装であり、実際には使用しないでください。代わりに、依存性注入に固執してください。これはテスト可能であり、デバッグを容易にします。
トーマスハンセン

1
この回答に依存関係注入を使用する方法の例と、それがどのようにテストをよりテストしやすくするかを教えていただけますか?
cjsimon

2

オブジェクトを静的に定義することはできませんが、これは機能します

final Class B{
  static $var;
  static function init(){
    self::$var = new A();
}
B::init();

1
Andreas Niedermair:phpの動作方法(app-cycle =単一のリクエスト)しかし、シングルトン(リクエストに含まれるもの)はphpで使用できます(phpでは、シングルトンは1つのインスタンスを持つオブジェクトです(アプリ内にサイクル)
ボレル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.