5

static次のようなキャッシュ目的で変数を使用するコードがある場合:

class BossParty
{
    // ...

    public function getTemplate()
    {
        static $template;

        if ($template == null)
        {
            $template = BossTemplate::get($this->templateID);
        }

        return $template;
    }

    // ...
}

$templateの異なるインスタンス間で持続しますBossPartyか? php.net をチェックしてみましたが、静的クラス変数に関する情報しか見つかりません。

4

3 に答える 3

7

はい、静的変数はクラスのインスタンス間で保持されます。

例:

<?php

class Test {
    public function __construct() {
        static $foo;

        if ($foo) {
            echo 'found';
        } else {
            $foo = 'foobar';
        }
    }
}

$test1 = new Test();
$test2 = new Test();
// output "found"

これは子孫クラスにも当てはまることに注意してください。Childを拡張したクラスがある場合、 (明示的または暗黙的に) をTest呼び出すと、同じ値の が使用されます。parent::__construct$foo

于 2011-05-16T10:19:36.380 に答える
2

@ lonesomeday、それはほとんど正しいようです。ただし、特に継承に関するフォローアップコメントに関連して、関数内の静的変数スコープの動作はより複雑なようです。すべての例で PHP 5.3.16 を使用しています。

要約:staticインスタンス関数内の変数のスコープに使用された場合のキーワードの動作は、継承と関数呼び出しスタックの場所の両方に基づいて異なるようです。

いくつかの例を次に示します。

まず、これは最初の例に似ています。クラスの__construct()メソッド内で静的変数をインスタンス化し、そのクラスの 2 つのインスタンスを作成し、その変数がどのように動作するかを確認します。

<?php
// Example 1
class A {
  public function __construct() {
    static $i = 0;
    $i++;
    $this->i = $i;
  }
}
$o1 = new A();
$o2 = new A();
printf("\$o1->i: %d\n", $o1->i); // outputs "$o1->i: 1"
printf("\$o2->i: %d\n", $o2->i); // outputs "$o2->i: 2"
?>

これまでのところ、驚きはありません。変数は 1 回 (0 に) インスタンス化され、個別のインスタンスごとにインクリメントされます。

クラスAを として拡張しB、それぞれの 1 つをインスタンス化すると (他のすべては同じままにしておきます)、同じ動作が得られます。

<?php
// Example 2
class A {
  public function __construct() {
    static $i = 0;
    $i++;
    $this->i = $i;
  }
}
class B extends A {}
$o1 = new A();
$o2 = new B();
printf("\$o1->i: %d\n", $o1->i); // outputs "$o1->i: 1"
printf("\$o2->i: %d\n", $o2->i); // outputs "$o2->i: 2"
?>

繰り返しますが、驚きはありません。最初の例に戻って、少し調整してみましょう。最初に、静的変数のインスタンス化/インクリメント呼び出しをメンバー メソッドに移動します。Bこのクラスのクラスを削除したことに注意してください。

<?php
// Example 3
class A {
  public function __construct() {
    $this->setI();
  }

  public function setI() {
    static $i = 0;
    $i++;
    $this->i = $i;
  }
}
$o1 = new A();
$o2 = new A();
printf("\$o1->i: %d\n", $o1->i); // outputs "$o1->i: 1"
printf("\$o2->i: %d\n", $o2->i); // outputs "$o2->i: 2"
?>

それでも同じ出力です。

ただし、 as として拡張AB、同じ構造をそのままにしておくと、次のようになります。

<?php
// Example 4
class A {
  public function __construct() {
    $this->setI();
  }

  public function setI() {
    static $i = 0;
    $i++;
    $this->i = $i;
  }
}
class B extends A {}
$o1 = new A();
$o2 = new B();
printf("\$o1->i: %d\n", $o1->i); // outputs "$o1->i: 1"
printf("\$o2->i: %d\n", $o2->i); // outputs "$o2->i: 1"
?>

出力に注意してください。他のすべてのケースで$o2->iは、これを除いて 2 になりました。

そのため、静的インスタンス化を拡張してインスタンス メソッドに移動すると、変数の新しいスコープが導入されたように見えA ます$iが、他のすべての場合、インスタンスはその静的変数のスコープを共有しています。

さらに紛らわしいのは、次の例を考えてみてください。前のものと同じですが、この場合、 classBは の独自の実装を取得しますsetI()。これは単に親クラスの実装に譲ります:

<?php
// Example 5
class A {
  public function __construct() {
    $this->setI();
  }
  public function setI() {
    static $i = 0;
    $i++;
    $this->i = $i;
  }
}
class B extends A {
  public function setI() {
    parent::setI();
  }
}
$o1 = new A();
$o2 = new B();
printf("\$o1->i: %d\n", $o1->i); // outputs "$o1->i: 1"
printf("\$o2->i: %d\n", $o2->i); // outputs "$o2->i: 2"
?>

ご覧のとおり、$o2->i現在は 2 に設定されています。これは、ほぼすべての場所で得られたものです (例 #4 を除く)。

これは、私には非常に直感に反するように思えます。異なるインスタンスがその変数に対して独自のスコープを取得するすべてのインスタンス (拡張クラスのインスタンスを含む) が同じスコープを共有することを期待します。

これが PHP のバグなのか、それとも予期された動作なのかはわかりません。静的変数スコープに関する PHP ドキュメントには、次のように書かれています。

静的変数はローカル関数スコープにのみ存在しますが、プログラムの実行がこのスコープを離れても値を失いません。

オブジェクトインスタンスのコンテキストで「関数スコープ」がどのように定義されているかについては詳しく説明していないため、例 4 のエッジケースが予想されるかどうかはわかりません。

于 2012-11-05T16:36:13.027 に答える
1

はい、ドキュメントにも記載されていますが、 Static Keywordの代わりにVariables Scopeセクションの下にあるため、見つからなかった可能性があります。

于 2011-05-16T10:21:25.563 に答える