検索
ホームページウェブフロントエンドjsチュートリアルPHP 静的バインディングの使用方法の詳細な説明

今回は、PHP の静的バインディングの使用方法について詳しく説明します。PHP の静的バインディングを使用する際の注意点を以下に示します。

基礎知識

1. 範囲解決演算子 (::)

  • は、静的メンバー、クラス定数にアクセスするために使用でき、クラス内の プロパティとメソッドをオーバーライドするためにも使用できます。

  • 3 つの特別なキーワード self、parent、static は、クラス定義内のプロパティまたはメソッドにアクセスするために使用されます。

  • parent は、親クラスでオーバーライドされたプロパティまたはメソッドを呼び出すために使用されます (それが表示される場合、対応するクラスの親クラスに解決されます)。

  • self は、このクラスのメソッドまたはプロパティを呼び出すために使用されます (これが表示される場合、対応するクラスに解析されます。$this との違いに注意してください。$this は、現在インスタンス化されているオブジェクトを指します)。

  • サブクラスが親クラスのメソッドをオーバーライドする場合、PHP は親クラスでオーバーライドされたメソッドを呼び出しません。親クラスのメソッドを呼び出すかどうかは子クラスに依存します。

2. PHP カーネルはクラスの継承実装を「コンパイルフェーズ」に配置します

<?php class A{
 const H = &#39;A&#39;;
 const J = &#39;A&#39;;
 static function testSelf(){
  echo self::H; //在编译阶段就确定了 self解析为 A
 }
}
class B extends A{
 const H = "B";
 const J = &#39;B&#39;;
 static function testParent(){
  echo parent::J; //在编译阶段就确定了 parent解析为A
 }
 /* 若重写testSelf则能输出“B”, 且C::testSelf()也是输出“B”
 static function testSelf(){
  echo self::H;
 }
 */
}
class C extends B{
 const H = "C";
 const J = &#39;C&#39;;
}
B::testParent();
B::testSelf();
echo "\n";
C::testParent();
C::testSelf();

実行結果:

AA
AA

結論:

self:: とparent:: が表示されます。 in 特定のクラス X の定義では、親クラスのメソッドがサブクラスでオーバーライドされない限り、対応するクラス X に解決されます。

3.Static(静的)キーワード

機能:

- 関数本体内の変数を変更するstaticキーワードは、静的なローカル変数を定義するために使用されます。
- クラスのメンバー関数とメンバー変数を変更するときに静的メンバーを宣言するために使用されます。
- (PHP5.3 以降) スコープ リゾルバー (::) の前の静的な遅延バインディングを表す特別なクラス。

例:

静的ローカル変数を定義する (出現: ローカル関数内)

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

<?php function test()
{
 static $count = 0;
 $count++;
 echo $count;
 if ($count < 10) {
  test();
 }
 $count--;
}

静的メソッド、静的属性を定義する

a) クラスの属性またはメソッドを静的として宣言し、クラスをインスタンス化せずに直接アクセスできるようにします。

b) クラスのインスタンス化されたオブジェクトを通じて静的プロパティにアクセスすることはできません (ただし、静的メソッドはアクセスできます)

c) アクセス制御 が指定されていない場合、プロパティとメソッドはデフォルトで public になります。

d) 静的メソッドではオブジェクトを呼び出す必要がないため、疑似変数 $this は静的メソッドでは使用できません。

e) -> 演算子を使用してオブジェクトから静的プロパティにアクセスすることはできません。

f) 非静的メソッドを静的に呼び出すと、E_STRICT レベルのエラーが発生します。

g) 他のすべての PHP 静的変数と同様、静的プロパティは式ではなくリテラルまたは定数にのみ初期化できます。したがって、静的プロパティは整数または配列に初期化できますが、別の変数や関数の戻り値に初期化したり、オブジェクトを指すことはできません。

a. 静的メソッドの例 (クラス メソッドの定義に表示)

<?php class Foo {
 public static function aStaticMethod() {
  // ...
 }
}
Foo::aStaticMethod();
$classname = &#39;Foo&#39;;
$classname::aStaticMethod(); // 自PHP 5.3.0后,可以通过变量引用类
?>

b. 静的属性の例 (クラス属性の定義に表示)

<?php class Foo
{
 public static $my_static = &#39;foo&#39;;
 public function staticValue() {
  return self::$my_static; //self 即 FOO类
 }
}
class Bar extends Foo
{
 public function fooStatic() {
  return parent::$my_static; //parent 即 FOO类
 }
}
print Foo::$my_static . "\n";
$foo = new Foo();
print $foo->staticValue() . "\n";
print $foo->my_static . "\n";  // Undefined "Property" my_static 
print $foo::$my_static . "\n";
$classname = 'Foo';
print $classname::$my_static . "\n"; // As of PHP 5.3.0
print Bar::$my_static . "\n";
$bar = new Bar();
print $bar->fooStatic() . "\n";
?>

c. 遅延静的バインディングに使用します。変数またはメソッドを変更するために使用されます)

以下は詳細な分析です

late static binding (遅延静的バインディング)

PHP 5.3.0以降、PHPには静的に参照するために使用されるlate static bindingと呼ばれる機能が追加されました。継承スコープ内のクラスを呼び出します。

1. 転送された通話と転送されていない通話

転送された通話:

は、self::、parent::、static::、および forward_static_call() の方法で行われる静的呼び出しを指します。

非転送呼び出し:

クラス名を明確に指定する静的呼び出し (Foo::foo() など)

非静的呼び出し ($foo->foo() など)

2.後期静的バインディング作業の原則

原理:存储了在上一个“非转发调用”(non-forwarding call)中的类名。意思是当我们调用一个转发调用的静态调用时,实际调用的类是上一个非转发调用的类。

例子分析:

<?php class A {
 public static function foo() {
  echo CLASS."\n";
  static::who();
 }
 public static function who() {
  echo CLASS."\n";
 }
}
class B extends A {
 public static function test() {
  echo "A::foo()\n";
  A::foo();
  echo "parent::foo()\n";
  parent::foo();
  echo "self::foo()\n";
  self::foo();
 }
 public static function who() {
  echo CLASS."\n";
 }
}
class C extends B {
 public static function who() {
  echo CLASS."\n";
 }
}
C::test();
/*
 * C::test(); //非转发调用 ,进入test()调用后,“上一次非转发调用”存储的类名为C
 *
 * //当前的“上一次非转发调用”存储的类名为C
 * public static function test() {
 *  A::foo(); //非转发调用, 进入foo()调用后,“上一次非转发调用”存储的类名为A,然后实际执行代码A::foo(), 转 0-0
 *  parent::foo(); //转发调用, 进入foo()调用后,“上一次非转发调用”存储的类名为C, 此处的parent解析为A ,转1-0
 *  self::foo(); //转发调用, 进入foo()调用后,“上一次非转发调用”存储的类名为C, 此处self解析为B, 转2-0
 * }
 *
 *
 * 0-0
 * //当前的“上一次非转发调用”存储的类名为A
 * public static function foo() {
 *  static::who(); //转发调用, 因为当前的“上一次非转发调用”存储的类名为A, 故实际执行代码A::who(),即static代表A,进入who()调用后,“上一次非转发调用”存储的类名依然为A,因此打印 “A”
 * }
 *
 * 1-0
 * //当前的“上一次非转发调用”存储的类名为C
 * public static function foo() {
 *  static::who(); //转发调用, 因为当前的“上一次非转发调用”存储的类名为C, 故实际执行代码C::who(),即static代表C,进入who()调用后,“上一次非转发调用”存储的类名依然为C,因此打印 “C”
 * }
 *
 * 2-0
 * //当前的“上一次非转发调用”存储的类名为C
 * public static function foo() {
 *  static::who(); //转发调用, 因为当前的“上一次非转发调用”存储的类名为C, 故实际执行代码C::who(),即static代表C,进入who()调用后,“上一次非转发调用”存储的类名依然为C,因此打印 “C”
 * }
 */
故最终结果为:
A::foo()
A
A
parent::foo()
A
C
self::foo()
A
C

3.更多静态后期静态绑定的例子

a)Self, Parent 和 Static的对比

<?php class Mango {
 function classname(){
  return CLASS;
 }
 function selfname(){
  return self::classname();
 }
 function staticname(){
  return static::classname();
 }
}
class Orange extends Mango {
 function parentname(){
  return parent::classname();
 }
 function classname(){
  return CLASS;
 }
}
class Apple extends Orange {
 function parentname(){
  return parent::classname();
 }
 function classname(){
  return CLASS;
 }
}
$apple = new Apple();
echo $apple->selfname() . "\n";
echo $apple->parentname() . "\n";
echo $apple->staticname();
?>
运行结果:
Mango
Orange
Apple

b)使用forward_static_call()

<?php class Mango
{
 const NAME = &#39;Mango is&#39;;
 public static function fruit() {
  $args = func_get_args();
  echo static::NAME, " " . join(&#39; &#39;, $args) . "\n";
 }
}
class Orange extends Mango
{
 const NAME = &#39;Orange is&#39;;
 public static function fruit() {
  echo self::NAME, "\n";
  forward_static_call(array(&#39;Mango&#39;, &#39;fruit&#39;), &#39;my&#39;, &#39;favorite&#39;, &#39;fruit&#39;);
  forward_static_call(&#39;fruit&#39;, &#39;my&#39;, &#39;father\&#39;s&#39;, &#39;favorite&#39;, &#39;fruit&#39;);
 }
}
Orange::fruit(&#39;NO&#39;);
function fruit() {
 $args = func_get_args();
 echo "Apple is " . join(&#39; &#39;, $args). "\n";
}
?>
运行结果:
Orange is
Orange is my favorite fruit
Apple is my father's favorite fruit

c)使用get_called_class()

<?php class Mango {
 static public function fruit() {
  echo get_called_class() . "\n";
 }
}
class Orange extends Mango {
 //
}
Mango::fruit();
Orange::fruit();
?>
运行结果:
Mango
Orange

应用

前面已经提到过了,引入后期静态绑定的目的是:用于在继承范围内引用静态调用的类。
所以, 可以用后期静态绑定的办法解决单例继承问题。

先看一下使用self是一个什么样的情况:

<?php // new self 得到的单例都为A。
class A
{
 protected static $_instance = null;
 protected function construct()
 {
  //disallow new instance
 }
 protected function clone(){
  //disallow clone
 }
 static public function getInstance()
 {
  if (self::$_instance === null) {
   self::$_instance = new self();
  }
  return self::$_instance;
 }
}
class B extends A
{
 protected static $_instance = null;
}
class C extends A{
 protected static $_instance = null;
}
$a = A::getInstance();
$b = B::getInstance();
$c = C::getInstance();
var_dump($a);
var_dump($b);
var_dump($c);
运行结果:
E:\code\php_test\apply\self.php:37:
class A#1 (0) {
}
E:\code\php_test\apply\self.php:38:
class A#1 (0) {
}
E:\code\php_test\apply\self.php:39:
class A#1 (0) {
}

通过上面的例子可以看到,使用self,实例化得到的都是类A的同一个对象

再来看看使用static会得到什么样的结果

<?php // new static 得到的单例分别为D,E和F。
class D
{
 protected static $_instance = null;
 protected function construct(){}
 protected function clone()
 {
  //disallow clone
 }
 static public function getInstance()
 {
  if (static::$_instance === null) {
   static::$_instance = new static();
  }
  return static::$_instance;
 }
}
class E extends D
{
 protected static $_instance = null;
}
class F extends D{
 protected static $_instance = null;
}
$d = D::getInstance();
$e = E::getInstance();
$f = F::getInstance();
var_dump($d);
var_dump($e);
var_dump($f);
运行结果:
E:\code\php_test\apply\static.php:35:
class D#1 (0) {
}
E:\code\php_test\apply\static.php:36:
class E#2 (0) {
}
E:\code\php_test\apply\static.php:37:
class F#3 (0) {
}

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

Vue如何使用动态刷新Echarts组件

vuex使用步骤详解

Vue.js里computed使用案例详解

以上がPHP 静的バインディングの使用方法の詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
JavaScript in Action:実際の例とプロジェクトJavaScript in Action:実際の例とプロジェクトApr 19, 2025 am 12:13 AM

現実世界でのJavaScriptのアプリケーションには、フロントエンドとバックエンドの開発が含まれます。 1)DOM操作とイベント処理を含むTODOリストアプリケーションを構築して、フロントエンドアプリケーションを表示します。 2)node.jsを介してRestfulapiを構築し、バックエンドアプリケーションをデモンストレーションします。

JavaScriptとWeb:コア機能とユースケースJavaScriptとWeb:コア機能とユースケースApr 18, 2025 am 12:19 AM

Web開発におけるJavaScriptの主な用途には、クライアントの相互作用、フォーム検証、非同期通信が含まれます。 1)DOM操作による動的なコンテンツの更新とユーザーインタラクション。 2)ユーザーエクスペリエンスを改善するためにデータを提出する前に、クライアントの検証が実行されます。 3)サーバーとのリフレッシュレス通信は、AJAXテクノロジーを通じて達成されます。

JavaScriptエンジンの理解:実装の詳細JavaScriptエンジンの理解:実装の詳細Apr 17, 2025 am 12:05 AM

JavaScriptエンジンが内部的にどのように機能するかを理解することは、開発者にとってより効率的なコードの作成とパフォーマンスのボトルネックと最適化戦略の理解に役立つためです。 1)エンジンのワークフローには、3つの段階が含まれます。解析、コンパイル、実行。 2)実行プロセス中、エンジンはインラインキャッシュや非表示クラスなどの動的最適化を実行します。 3)ベストプラクティスには、グローバル変数の避け、ループの最適化、constとletsの使用、閉鎖の過度の使用の回避が含まれます。

Python vs. JavaScript:学習曲線と使いやすさPython vs. JavaScript:学習曲線と使いやすさApr 16, 2025 am 12:12 AM

Pythonは、スムーズな学習曲線と簡潔な構文を備えた初心者により適しています。 JavaScriptは、急な学習曲線と柔軟な構文を備えたフロントエンド開発に適しています。 1。Python構文は直感的で、データサイエンスやバックエンド開発に適しています。 2。JavaScriptは柔軟で、フロントエンドおよびサーバー側のプログラミングで広く使用されています。

Python vs. JavaScript:コミュニティ、ライブラリ、リソースPython vs. JavaScript:コミュニティ、ライブラリ、リソースApr 15, 2025 am 12:16 AM

PythonとJavaScriptには、コミュニティ、ライブラリ、リソースの観点から、独自の利点と短所があります。 1)Pythonコミュニティはフレンドリーで初心者に適していますが、フロントエンドの開発リソースはJavaScriptほど豊富ではありません。 2)Pythonはデータサイエンスおよび機械学習ライブラリで強力ですが、JavaScriptはフロントエンド開発ライブラリとフレームワークで優れています。 3)どちらも豊富な学習リソースを持っていますが、Pythonは公式文書から始めるのに適していますが、JavaScriptはMDNWebDocsにより優れています。選択は、プロジェクトのニーズと個人的な関心に基づいている必要があります。

C/CからJavaScriptへ:すべてがどのように機能するかC/CからJavaScriptへ:すべてがどのように機能するかApr 14, 2025 am 12:05 AM

C/CからJavaScriptへのシフトには、動的なタイピング、ゴミ収集、非同期プログラミングへの適応が必要です。 1)C/Cは、手動メモリ管理を必要とする静的に型付けられた言語であり、JavaScriptは動的に型付けされ、ごみ収集が自動的に処理されます。 2)C/Cはマシンコードにコンパイルする必要がありますが、JavaScriptは解釈言語です。 3)JavaScriptは、閉鎖、プロトタイプチェーン、約束などの概念を導入します。これにより、柔軟性と非同期プログラミング機能が向上します。

JavaScriptエンジン:実装の比較JavaScriptエンジン:実装の比較Apr 13, 2025 am 12:05 AM

さまざまなJavaScriptエンジンは、各エンジンの実装原則と最適化戦略が異なるため、JavaScriptコードを解析および実行するときに異なる効果をもたらします。 1。語彙分析:ソースコードを語彙ユニットに変換します。 2。文法分析:抽象的な構文ツリーを生成します。 3。最適化とコンパイル:JITコンパイラを介してマシンコードを生成します。 4。実行:マシンコードを実行します。 V8エンジンはインスタントコンピレーションと非表示クラスを通じて最適化され、Spidermonkeyはタイプ推論システムを使用して、同じコードで異なるパフォーマンスパフォーマンスをもたらします。

ブラウザを超えて:現実世界のJavaScriptブラウザを超えて:現実世界のJavaScriptApr 12, 2025 am 12:06 AM

現実世界におけるJavaScriptのアプリケーションには、サーバー側のプログラミング、モバイルアプリケーション開発、モノのインターネット制御が含まれます。 2。モバイルアプリケーションの開発は、ReactNativeを通じて実行され、クロスプラットフォームの展開をサポートします。 3.ハードウェアの相互作用に適したJohnny-Fiveライブラリを介したIoTデバイス制御に使用されます。

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SecLists

SecLists

SecLists は、セキュリティ テスターの究極の相棒です。これは、セキュリティ評価中に頻繁に使用されるさまざまな種類のリストを 1 か所にまとめたものです。 SecLists は、セキュリティ テスターが必要とする可能性のあるすべてのリストを便利に提供することで、セキュリティ テストをより効率的かつ生産的にするのに役立ちます。リストの種類には、ユーザー名、パスワード、URL、ファジング ペイロード、機密データ パターン、Web シェルなどが含まれます。テスターはこのリポジトリを新しいテスト マシンにプルするだけで、必要なあらゆる種類のリストにアクセスできるようになります。

PhpStorm Mac バージョン

PhpStorm Mac バージョン

最新(2018.2.1)のプロフェッショナル向けPHP統合開発ツール

AtomエディタMac版ダウンロード

AtomエディタMac版ダウンロード

最も人気のあるオープンソースエディター

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強力な PHP 統合開発環境