thinkphp 5.1フレームワーク解析(三):容器と依存注入
6466 ワード
前の記事ではThinkPHPがどのように自動ロードを実現するかについてお話ししましたが、見たいならThinkPHP 5を見ることができます.1ソースコードの浅い分析(二)自動ロードメカニズム
この記事を読む前にIOC、DI、Facadeの基本的な知識を身につけていただきたいと思いますが、ご理解いただけない場合は、まずいくつかの記事をご覧ください.
制御反転(IoC)と依存注入(DI)の詳細な理解
では本題に入ります.
サービスコール
分析フレームワークに基づくエントリスクリプトファイル
上記の
ここでこそIOCコンテナ機能を使って、appというコンテナ1を取得
Containerに入ってから彼のクラス属性を紹介します
getメソッドへのアクセス
このコードは、現在のコンテナのインスタンス(単一例)を取得し、インスタンス化することです.
makeメソッドへのアクセス
分割してみましょう
このコードは、
前述したように、
ここでは、コンテナにロードするクラスが以前に別名をバインドしたかどうかを確認します(バインドされている場合は、インスタンス化します. がなければ、クラス名であると認定し、直接呼び出します.3
ファセットモード
上のIOC容器では、
コードを記述する際に
helloメソッドを呼び出すコードは、次のようになります.
次に、このクラスに静的エージェントクラス
このクラスライブラリが
結果は
率直に言って、Facade機能はクラスをインスタンス化せずに静的に呼び出すことができます.
Facadeの動作原理 Facedeコア実装原理は、FacadeにIoC容器を事前に注入することである. は、iocコンテナにバインドされたkeyと同様にクラスの変数を定義するサービスプロバイダの外観クラスを定義する. 静的マジックによる方法_callStaticは、現在呼び出すhelloメソッド を得ることができる. static:$ioc->make('Test');
なぜFacadeを使うのか
Facadesを使用する上で最も重要なのは、長いクラス名を手動で注入したり構成したりする必要がなく、簡単で覚えやすい構文を提供することです.さらに,PHP静的方法に対する独自の呼び出しにより,試験が非常に容易になった.
ここではContainerクラスの場所が見つからないので、自動ロードメカニズムを実行してContainerの場所を探してロードします.↩
実例の山を木に掛けて、必要なときに使っています.↩
ダイレクトコールは反射を使用した結果で、反射に関する知識点は自分で見ています.↩
この記事を読む前にIOC、DI、Facadeの基本的な知識を身につけていただきたいと思いますが、ご理解いただけない場合は、まずいくつかの記事をご覧ください.
制御反転(IoC)と依存注入(DI)の詳細な理解
では本題に入ります.
サービスコール
分析フレームワークに基づくエントリスクリプトファイル
index.php
//
require __DIR__ . '/../thinkphp/base.php';
// Request Config
//
Container::get('app')->run()->send();
上記の
base.php
の役割は、自動ロードメカニズムのロードと異常処理、およびログ機能のオンです.//
Container::get('app')->run()->send();
ここでこそIOCコンテナ機能を使って、appというコンテナ1を取得
Containerに入ってから彼のクラス属性を紹介します
protected static $instance; // , ,
protected $instances = []; //
protected $bind = []; //
protected $name = []; //
$instances
は、登録ツリーモード2が実現され、値が格納されるarray (
'think\\App' => App ,
'think\\Env' => Env ,
'think\\Config' => Config ,
...
)
bind
は、初期化時に初期データの山をロードし、クラス名とクラス名のマッピング関係を記録します.protected $bind = [
'app' => 'think\\App',
'build' => 'think\\Build',
'cache' => 'think\\Cache',
'config' => 'think\\Config',
'cookie' => 'think\\Cookie',
...
]
name
およびbind
属性レコードの値は、クラス別名とクラス名のマッピング関係で類似しています.違いは、name
がインスタンス化されたマッピング関係を記録していることである.getメソッドへのアクセス
public static function get($abstract, $vars = [], $newInstance = false)
{
return static::getInstance()->make($abstract, $vars, $newInstance);
}
このコードは、現在のコンテナのインスタンス(単一例)を取得し、インスタンス化することです.
makeメソッドへのアクセス
public function make($abstract, $vars = [], $newInstance = false)
{
if (true === $vars) {
//
$newInstance = true;
$vars = [];
}
// ,
$abstract = isset($this->name[$abstract]) ? $this->name[$abstract] : $abstract;
// , ,
if (isset($this->instances[$abstract]) && !$newInstance) {
return $this->instances[$abstract];
}
// , 'app' => 'think\\App',
if (isset($this->bind[$abstract])) {
$concrete = $this->bind[$abstract];
// ThinkPHP ,
if ($concrete instanceof Closure) {
$object = $this->invokeFunction($concrete, $vars);
} else {
// , , think\\App
$this->name[$abstract] = $concrete;
return $this->make($concrete, $vars, $newInstance);
}
} else {
//
$object = $this->invokeClass($abstract, $vars);
}
if (!$newInstance) {
$this->instances[$abstract] = $object;
}
//
return $object;
}
分割してみましょう
if (true === $vars) {
//
$newInstance = true;
$vars = [];
}
このコードは、
make($abstract, true)
を使用して関数を呼び出すことができ、毎回新しいインスタンスを得ることができます.(この方式はあまりよくないと思いますが、変数ごとに意味が明確ではありません)// ,
$abstract = isset($this->name[$abstract]) ? $this->name[$abstract] : $abstract;
// , ,
if (isset($this->instances[$abstract]) && !$newInstance) {
return $this->instances[$abstract];
}
前述したように、
name
にはインスタンス化された別名=>クラス名のマッピング関係が格納されており、ここでクラス名を取り出してみます.このクラスがインスタンス化されている場合は、直接戻ります.// , 'app' => 'think\\App',
if (isset($this->bind[$abstract])) {
$concrete = $this->bind[$abstract];
// ThinkPHP ,
if ($concrete instanceof Closure) {
$object = $this->invokeFunction($concrete, $vars);
} else {
// , , think\\App
$this->name[$abstract] = $concrete;
return $this->make($concrete, $vars, $newInstance);
}
} else {
//
$object = $this->invokeClass($abstract, $vars);
}
ここでは、コンテナにロードするクラスが以前に別名をバインドしたかどうかを確認します(
bind('classNickName')
に直接設定することもできます).ファセットモード
上のIOC容器では、
$ioc->get('test');
testクラスを手に入れることができ、私たちの$user->hello()
の方法で挨拶をします.顔ができたら、直接使ってもいいです.Test::hello()
静的呼び出しについて説明します.コードを記述する際に
facade
パケットのクラスを用いてインタフェースの静的呼び出しを行うことが多いが,ここでは公式サイトの例を挙げる.app\common\Test
クラスを定義すると、hello
ダイナミックメソッドがあります.
helloメソッドを呼び出すコードは、次のようになります.
$test = new \app\common\Test;
echo $test->hello('thinkphp'); // hello,thinkphp
次に、このクラスに静的エージェントクラス
app\facade\Test
を定義します(このクラス名は必ずしもTest
クラスと一致する必要はありませんが、通常は管理を容易にするために、名前の統一を維持することをお勧めします).
このクラスライブラリが
think\Facade
を継承する限り、動的クラスapp\common\Test
の動的メソッドを静的に呼び出すことができ、例えば、上記のコードを変更することができる.// hello
echo \app\facade\Test::hello('thinkphp');
結果は
hello,thinkphp
も出力されます.率直に言って、Facade機能はクラスをインスタンス化せずに静的に呼び出すことができます.
Facadeの動作原理
なぜFacadeを使うのか
Facadesを使用する上で最も重要なのは、長いクラス名を手動で注入したり構成したりする必要がなく、簡単で覚えやすい構文を提供することです.さらに,PHP静的方法に対する独自の呼び出しにより,試験が非常に容易になった.
ここではContainerクラスの場所が見つからないので、自動ロードメカニズムを実行してContainerの場所を探してロードします.↩
実例の山を木に掛けて、必要なときに使っています.↩
ダイレクトコールは反射を使用した結果で、反射に関する知識点は自分で見ています.↩