静的変数を初期化する方法


207

私はこのコードを持っています:

private static $dates = array(
  'start' => mktime( 0,  0,  0,  7, 30, 2009),  // Start date
  'end'   => mktime( 0,  0,  0,  8,  2, 2009),  // End date
  'close' => mktime(23, 59, 59,  7, 20, 2009),  // Date when registration closes
  'early' => mktime( 0,  0,  0,  3, 19, 2009),  // Date when early bird discount ends
);

これは私に次のエラーを与えます:

解析エラー:構文エラー、予期しない「(」、「)」が/home/user/Sites/site/registration/inc/registration.class.incの19行目

だから、私は何か間違ったことをしていると思います...しかし、そうでなければどうすればこれを行うことができますか?mktimeのものを通常の文字列に変更すると、動作します。だから私はそれをある程度できることを知っていますような..

誰かがいくつかの指針を持っていますか?



2
最初の答えは過票です。参照してくださいstackoverflow.com/a/4470002/632951
Pacerier

1
@Pacerier私はそうは思いません。回答2回答1に
Kontrollfreak 2015

2
@Pacerierは10人に尋ねますが、誰もそれを好みません。
バッファロー

回答:


345

PHPは、イニシャライザ内の重要な式を解析できません。

私はクラスの定義の直後にコードを追加することによってこれを回避することを好みます:

class Foo {
  static $bar;
}
Foo::$bar = array(…);

または

class Foo {
  private static $bar;
  static function init()
  {
    self::$bar = array(…);
  }
}
Foo::init();

PHP 5.6で一部の式を処理できるようになりました。

/* For Abstract classes */
abstract class Foo{
    private static function bar(){
        static $bar = null;
        if ($bar == null)
            bar = array(...);
        return $bar;
    }
    /* use where necessary */
    self::bar();
}

135
PHPは大好きですが、ときどき奇妙なこともあります。
マルコデマイオ

6
私はこれが古いことを知っていますが、私もこの方法を使用しています。ただし、Foo :: init()が呼び出されないこともあります。理由を突き止めることはできませんでしたが、すべてを認識させたいと思っていました。
5

1
@porneL、プライベート変数にアクセスできないため、最初の方法は機能しません。2番目の方法は機能しますが、init醜い方法で公開する必要があります。より良い解決策は何ですか?
Pacerier 2013

2
@Pacerier最初のメソッドは、理由のためにパブリックプロパティを使用します。私の知る限り、現時点でPHPに最適なソリューションはありません(ただし、Tjeerd Visserの答えは悪くありません)。クラスローダーでハックを非表示にしても、ハックがなくなるわけではなく、誤った継承が強制され、予期せず壊れる可能性がある(たとえば、ファイルが明示的にrequire()dされている場合)、ちょっとした賢さです。
Kornel 2013

1
@porneL単純な配列は、PHP 5.6.xでは機能しますが、RFCでは言及されていません。例:class Foo {public static $bar = array(3 * 4, "b" => 7 + 8);} var_dump(Foo::$bar);
パン

32

クラスのロードを制御できる場合は、そこから静的初期化を行うことができます。

例:

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

クラスローダーで、次の操作を行います。

include($path . $klass . PHP_EXT);
if(method_exists($klass, 'static_init')) { $klass::staticInit() }

より重いソリューションは、ReflectionClassとのインターフェースを使用することです。

interface StaticInit { public static function staticInit() { } }
class MyClass implements StaticInit { public static function staticInit() { } }

クラスローダーで、次の操作を行います。

$rc = new ReflectionClass($klass);
if(in_array('StaticInit', $rc->getInterfaceNames())) { $klass::staticInit() }

これは、c#の静的コンストラクターに多少似ていますが、私は古くから非常によく似たものを使用してきました。
クリス

@EmanuelLandeholm、それではメソッド1の方が高速ですか、それともメソッド2の方が高速ですか?
Pacerier 2013

@クリスそれは偶然ではありません。答えたとき、私はc#に触発されました。
Emanuel Landeholm 2013

1
@Pacerier証明はありませんが、ReflectionClass()でオーバーヘッドが増える可能性があると思います。大藤、第一の方法は、というやや危険な仮定作る任意の中で「static_init」と呼ばれる方法いずれかのクラスローダによってロードされたクラスは静的初期化子です。これにより、バグの追跡が困難になる可能性があります。サードパーティのクラスで。
Emanuel Landeholm 2013

23

静的変数を機能させる方法を見つけるのではなく、単にゲッター関数を作成することを好みます。特定のクラスに属する配列が必要で、実装がはるかに簡単な場合にも役立ちます。

class MyClass
{
   public static function getTypeList()
   {
       return array(
           "type_a"=>"Type A",
           "type_b"=>"Type B",
           //... etc.
       );
   }
}

リストが必要なときはいつでも、getterメソッドを呼び出すだけです。例えば:

if (array_key_exists($type, MyClass::getTypeList()) {
     // do something important...
}

11
これは洗練されたソリューションですが、主に配列が初期化される可能性のある時間、つまり大量のヒープ割り当てのため、パフォーマンス上の理由から理想的とは言えません。phpはCで書かれているので、変換によって、呼び出しごとに配列へのポインターを返す関数に解決されると思います...ちょうど2セントです。
zeboidlund 2012

さらに、PHPでは関数呼び出しは負荷が高いため、必要がない場合は回避するのが最善です。
Mark Rose

14
「不要な場合は回避することをお勧めします」-それほどでもありません。ボトルネックになる可能性がある場合は回避してください。そうでなければ、それは時期尚早の最適化です。
psycho brm 2013年

2
@blissfreak-クラスに静的プロパティを作成し、getTypeList()でチェックして、すでに初期化されているかどうかを確認し、それを返す場合、実現は回避できます。まだ初期化されていない場合は、初期化してその値を返します。
grantwparks 2013年

12
真剣に関数呼び出しを避けようとはしません。関数は構造化プログラミングの基礎です。
grantwparks 2013年

11

Tjeerd VisserとporneLの回答を組み合わせて使用​​します。

class Something
{
    private static $foo;

    private static getFoo()
    {
        if ($foo === null)
            $foo = [[ complicated initializer ]]
        return $foo;
    }

    public static bar()
    {
        [[ do something with self::getFoo() ]]
    }
}

しかし、さらに優れた解決策は、静的メソッドを廃止してシングルトンパターンを使用することです。次に、コンストラクターで複雑な初期化を行います。または、それを「サービス」にして、DIを使用して、それを必要とする任意のクラスに挿入します。


10

これは複雑すぎて定義に設定できません。ただし、定義をnullに設定してから、コンストラクターでそれを確認し、変更されていない場合は設定します。

private static $dates = null;
public function __construct()
{
    if (is_null(self::$dates)) {  // OR if (!is_array(self::$date))
         self::$dates = array( /* .... */);
    }
}

10
しかし、コンストラクターはインスタンス化されない抽象クラスで役に立ちますか?
スビッシュ

抽象クラスは、完成してインスタンス化しない限り、有効に使用できません。上記の設定は、変数が使用される前にどこかで呼び出される限り、特にコンストラクターで行う必要はありません。
アリスターブルマン

静的変数が必要になる前にコンストラクターが呼び出されると想定するのは良い考えではありません。多くの場合、インスタンスを作成する前に静的な値が必要です。
ToolmakerSteve

4

コードのこの部分で関数呼び出しを行うことはできません。他のコードが実行する前に実行されるinit()タイプのメソッドを作成すると、変数を設定できます。


init()タイプのメソッド?例を挙げていただけますか?それはC#の静的コンストラクタのようなものですか?
スビッシュ

@Svish:いいえ。通常の静的メソッドとして、クラス定義のすぐ下で呼び出す必要があります。
Vladislav Rastrusny、2010年

4

PHP 7.0.1では、これを定義することができました。

public static $kIdsByActions = array(
  MyClass1::kAction => 0,
  MyClass2::kAction => 1
);

そして、次のように使用します。

MyClass::$kIdsByActions[$this->mAction];

FWIW:あなたが示すものはPHP 7を必要としません。それは時間の問題を頼まれた時に罰金を働いた:「私は通常の文字列ではmktimeのものを変更した場合、それが動作します」 このスレッドが探しているのは、初期化で1つ以上の関数を呼び出す必要がある場合にstaticを初期化する手法です。
ToolmakerSteve

3

最善の方法は、次のようなアクセサを作成することです。

/**
* @var object $db : map to database connection.
*/
public static $db= null; 

/**
* db Function for initializing variable.   
* @return object
*/
public static function db(){
 if( !isset(static::$db) ){
  static::$db= new \Helpers\MySQL( array(
    "hostname"=> "localhost",
    "username"=> "root",
    "password"=> "password",
    "database"=> "db_name"
    )
  );
 }
 return static::$db;
}

次に、static :: db();を実行できます。またはself :: db(); どこからでも。


-1

以下は、コード例の中で役立つと思われるポインタです。初期化関数が1回だけ呼び出される方法に注意してください。

また、あなたが電話を反転場合StaticClass::initializeStStateArr()$st = new StaticClass()同じ結果を得るでしょう。

$ cat static.php
<?php

class StaticClass {

  public static  $stStateArr = NULL;

  public function __construct() {
    if (!isset(self::$stStateArr)) {
      self::initializeStStateArr();
    }
  }

  public static function initializeStStateArr() {
    if (!isset(self::$stStateArr)) {
      self::$stStateArr = array('CA' => 'California', 'CO' => 'Colorado',);
      echo "In " . __FUNCTION__. "\n";
    }
  }

}

print "Starting...\n";
StaticClass::initializeStStateArr();
$st = new StaticClass();

print_r (StaticClass::$stStateArr);

どの利回り:

$ php static.php
Starting...
In initializeStStateArr
Array
(
    [CA] => California
    [CO] => Colorado
)

2
ただし、コンストラクターはパブリックNONSTATIC関数であるため、クラス(オブジェクト)のインスタンスを作成したことに注意してください。質問:PHPは静的コンストラクタのみをサポートしていますか(インスタンスの作成はサポートしていません。たとえば、Javaのようにstatic { /* some code accessing static members*/ }
Mitja Gustin
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.