@ 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 として拡張A
しB
、同じ構造をそのままにしておくと、次のようになります。
<?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 のエッジケースが予想されるかどうかはわかりません。