PHPインタビューの準備:静的キーワード

彼らがインタビューで難しい質問をするのが好きなのは秘密ではありません。 常に適切であるとは限らず、現実と常に関連しているとは限りませんが、事実は残っています。 もちろん、質問は議論の余地があり、時には一見すると馬鹿げているように見える質問は、実際にあなたが書いている言語をどれだけ知っているかをチェックすることを目的としています。



画像



これらの質問の1つを解析してみましょう。PHPで「静的」という言葉は何を意味し、なぜ使用されているのですか?



PHPの静的キーワードには3つの異なる意味があります。 言語に登場するように、年代順に分析します。



最初の値は静的なローカル変数です



function foo() { $a = 0; echo $a; $a = $a + 1; } foo(); // 0 foo(); // 0 foo(); // 0
      
      







PHPでは、変数はローカルです。 これは、関数(メソッド)内で値を定義して受け取った変数は、この関数(メソッド)の実行中にのみ存在することを意味します。 メソッドを終了すると、ローカル変数は破棄され、再入力すると再び作成されます。 上記のコードでは、このようなローカル変数は$ a変数です-foo()関数内にのみ存在し、この関数が呼び出されるたびに再作成されます。 コードの次の行で関数が処理を終了し、変数の値が失われるため、このコードの変数の増分は無意味です。 foo()関数を何度呼び出しても、常に0が出力されます...



ただし、割り当ての前に静的キーワードを設定すると、すべてが変わります。



 function foo() { static $a = 0; echo $a; $a = $a + 1; } foo(); // 0 foo(); // 1 foo(); // 2
      
      







ローカル変数に値を割り当てる前に記述された静的キーワードには、次の効果があります。

  1. 割り当ては、関数が最初に呼び出されたときに一度だけ実行されます
  2. この方法でマークされた変数の値は、関数の終了後に保存されます
  3. 関数への後続の呼び出しでは、変数は割り当ての代わりに、以前に保存された値を受け取ります


静的という単語のこの使用は、 静的ローカル変数と呼ばれます



静的変数の落とし穴


もちろん、PHPの場合と同様に、「落とし穴」なしではできません。



ストーン1-定数または定数式のみを静的変数に割り当てることができます。 コードは次のとおりです。

 static $a = bar();
      
      





必然的にパーサーエラーが発生します。 幸いなことに、バージョン5.6から、定数だけでなく、定数式(たとえば、「1 + 2」または「[1、2、3]」)、つまり、他のコードとは独立した式を割り当てることが可能になりました。コンパイル時に計算できます



2番目の石-メソッドは1つのコピーに存在します。

ここではすべてが少し複雑です。 本質を理解するために、コードを提供します。

 class A { public function foo() { static $x = 0; echo ++$x; } } $a1 = new A; $a2 = new A; $a1->foo(); // 1 $a2->foo(); // 2 $a1->foo(); // 3 $a2->foo(); // 4
      
      





「異なるオブジェクト-異なるメソッド」の直感的な期待に反して、この例では、PHPの動的メソッドは「乗算しない」ことが明確にわかります。 このクラスのオブジェクトが100個ある場合でも、メソッドは1つのインスタンスにのみ存在し、呼び出しごとに異なる$ thisがスローされます。



この動作は、準備が整っていない開発者にとっては予期しないものであり、エラーの原因となる可能性があります。 クラス(およびメソッド)の継承により、新しいメソッドがまだ作成されることに注意してください。



 class A { public function foo() { static $x = 0; echo ++$x; } } class B extends A { } $a1 = new A; $b1 = new B; $a1->foo(); // 1 $b1->foo(); // 1 $a1->foo(); // 2 $b1->foo(); // 2
      
      







結論:PHPの動的メソッドは、オブジェクトではなくクラスのコンテキストに存在します。 そして、実行時にのみ「$ this = current_object」の置換が行われます



2番目の値-静的プロパティとクラスメソッド



PHPオブジェクトモデルでは、オブジェクト-クラスのインスタンスだけでなく、クラス全体のプロパティとメソッドも設定できます。 これにはstaticキーワードも使用されます。



 class A { public static $x = 'foo'; public static function test() { return 42; } } echo A::$x; // 'foo' echo A::test(); // 42
      
      





これらのプロパティとメソッドにアクセスするには、CLASS_NAME :: $ Variable_NAMEおよびCLASS_NAME :: MethodName()などの二重コロン構造( "Paamayim Nekudotayim")が使用されます。



静的プロパティと静的メソッドには、独自の特性と、知っておく必要がある「落とし穴」があることは言うまでもありません。



最初の機能はありふれたものです-これはありません。 実際、これは静的メソッドの定義そのものに由来します。これはオブジェクトではなくクラスに関連付けられているため、動的メソッドの現在のオブジェクトを示す擬似変数$ thisは使用できません。 これは完全に論理的です。



ただし、他の言語とは異なり、PHPは解析またはコンパイルの段階で「これが静的メソッドで記述されている」という状況を判断しないことを知っておく必要があります。 静的メソッド内で$ thisを使用してコードを実行しようとすると、同様のエラーがランタイムでのみ発生します。



このようなコード:

 class A { public $id = 42; static public function foo() { echo $this->id; } }
      
      





foo()メソッドを不適切に使用しようとするまで、エラーは発生しません。

 $a = new A; $a->foo();
      
      



(そしてすぐに「致命的なエラー:オブジェクトコンテキストにないときに$ thisを使用する」を取得します)



2番目の機能-静的は公理ではありません!

 class A { static public function foo() { echo 42; } } $a = new A; $a->foo();
      
      





はい、はい。 静的メソッドは、コードに$ thisが含まれていない場合、オブジェクトメソッドのように動的コンテキストで呼び出すことができます。 これはPHPのバグではありません。



その逆は完全に真実ではありません:

 class A { public function foo() { echo 42; } } A::foo();
      
      





$ thisを使用しない動的メソッドは、静的コンテキストで実行できます。 ただし、レベルE_STRICTの「非静的メソッドA :: foo()を静的に呼び出さないでください」という警告が表示されます。 厳密にコード標準に従うか、警告を抑制するかはあなた次第です。 もちろん、最初のものが望ましいです。



ちなみに、上記のすべてはメソッドにのみ適用されます。 「->」を使用して静的プロパティを使用することはできず、致命的なエラーが発生します。



3番目の意味、これは最も難しいと思われる-遅い静的バインディング



PHP言語の開発者は、キーワード「static」の2つの値で停止することはなく、バージョン5.3では、同じ単語によって実装される言語の別の「機能」を追加しました。 「遅延静的バインディング」またはLSB(遅延静的バインディング)と呼ばれます。



LSBの本質は、簡単な例で理解するのが最も簡単です。



 class Model { public static $table = 'table'; public static function getTable() { return self::$table; } } echo Model::getTable(); // 'table'
      
      





PHPのselfキーワードは、常に「この単語が書かれているクラスの名前」を意味します。 この場合、selfはModelクラスに置き換えられ、self :: $ tableはModel :: $ tableに置き換えられます。

この言語機能は、「早期静的バインディング」と呼ばれます。 なぜ早く? 自己と具体的なクラス名のバインディングはランタイムではなく、コードの解析とコンパイルの初期段階で発生するためです。 しかし、「静的」-静的なプロパティとメソッドについて話しているからです。



コードを少し変更しましょう。



 class Model { public static $table = 'table'; public static function getTable() { return self::$table; } } class User extends Model { public static $table = 'users'; } echo User::getTable(); // 'table'
      
      







これで、この状況でPHPが直観的でない理由がわかりました。 selfは、Userクラスがまだ知られていないときにModelクラスに関連付けられていたため、Modelを指します。



になる方法



このジレンマを解決するために、実行時段階で「後期」バインディングメカニズムが考案されました。 それは非常に簡単に動作します-「self」という単語の代わりに「static」と記述するだけで、コードが記述されたクラスではなく、指定されたコードを呼び出すクラスとの接続が確立されます。

 class Model { public static $table = 'table'; public static function getTable() { return static::$table; } } class User extends Model { public static $table = 'users'; } echo User::getTable(); // 'users'
      
      







これが不可解な「後期静的バインディング」です。



PHPの便宜上、「静的」という言葉に加えて、コードが現在実行されているクラスのコンテキストで通知する特別な関数get_called_class()もあります。



素晴らしい就職面接をしてください!



マニュアルへの便利なリンクのリスト:




All Articles