依存性注入と制御の反転
依存性注入 この用語に初めて触れたとき、私は今でも少し混乱しています。そこで、今日は Laravel での依存性注入について説明します。それをよく理解してください。 コントロールの反転 第一印象とはとても奥深い言葉です。 。 。リバースコントロールっぽい?分かりませんか?それからまっすぐにしてください!
私はあなたなしでは生きていけません、ならば、あなたは私の依存物です。 率直に言うと、
は私のものではありませんが、私に必要なものであり、私が依存しているものです。外部から提供する必要があるものはすべて依存関係の注入が必要です。
コードで説明しましょう:
class Boy { protected $girl; public function __construct(Girl $girl) { $this->girl = $girl; }}class Girl { ...}$boy = new Boy(); // Error; Boy must have girlfriend!// so 必须要给他一个女朋友才行 $girl = new Girl();$boy = new Boy($girl); // Right! So Happy!
上記のコードから、Boy は Girl に強く依存しており、構築中に Girl のインスタンスを注入する必要があることがわかります。
では、なぜ依存性注入という概念があるのでしょうか? 依存性注入はどのような問題を解決しますか?
上記のコードを、学習時に書いたコードに変更してみましょう:
class Boy { protected $girl; public function __construct() { $this->girl = new Girl(); }}
この方法と前の方法の違いは何ですか?
ボーイのガールフレンドがボーイの体にハードコードされていることがわかります。 。 。 ボーイは生まれ変わって、違うタイプのガールフレンドが欲しくなるたびに、裸にならなければなりません。 。 。 (⊙o⊙)…
ある日、ボーイはロリガールが大好きで、彼女を彼女にしてほしかったのです。 。 。何をするか? 自分自身を生まれ変わらせます。 。 。自分自身を明らかにしましょう。 。 。女の子を捨てなさい。 。 。ロリガールを中に押し込んでください。 。 。
rreeeある日、ボーイはユウお姉さんに恋をしてしまいました…(⊙o⊙)… ボーイはとてもイライラしていました。 。 。
気分が良くないですか?私に誠実に接してくれる人に出会うたびに、私はこうやって自分を苦しめなければなりません。 。 。
少年は言いました、私は強くなりたいです。何度も変えられたくない!
分かった、ボーイを強くしましょう:
rreeeボーイは、ついに自分自身を開かずに別の人生を経験できることにとても満足しています。 。 。とても幸せです!
だからこそ、依存性注入の概念が存在します。依存性注入は次の問題を解決します:
IOC の概念を理解しましょう。 制御の反転 (Inversion Of Control、IOC)
制御の反転は、コンピューター コード間の結合を減らすために使用できるオブジェクト指向プログラミングの設計原則です。最も一般的な方法は Dependency Injection (DI) と呼ばれ、もう 1 つは「Dependency Lookup」と呼ばれます。制御の反転により、オブジェクトが作成されると、システム内のすべてのオブジェクトを制御する外部エンティティが、依存するオブジェクトの参照をそれに渡します。依存関係がオブジェクトに注入されるとも言えます。 言い換えると、制御システムが必要です。この制御システムでは、いくつかのオブジェクトのエンティティ、またはオブジェクトの説明を保存し、オブジェクトの作成時にそのオブジェクトが依存するオブジェクトの参照を渡します。 Laravelのサービスコンテナは、laravelの核となるこの効率的な制御システムです。 laravel が自動依存関係注入をどのように実装するかを見てみましょう。
laravel での依存性注入
class LoliGirl {}class Boy { protected $girl; public function __construct() { // $this->girl = new Girl(); // sorry... $this->girl = new LoliGirl(); }}
この例では、PurchasePodcast ジョブは、ポッドキャストが購入されたときに電子メールを送信する必要があります。電子メールを送信できるサービスを注入します
サービスは注入されるため、簡単に「モック」したり、ダミーの実装を作成したりすることもできます。アプリケーションをテストするときのメーラーです。laravelの依存関係注入と言えば、laravelのサービスコンテナを理解する必要があります
サービスコンテナ(サービスコンテナ)Laravelサービスコンテナは、クラスの依存関係を管理し、依存関係注入を実行するための強力なツールです。依存関係の注入とは、本質的に次のことを意味する派手なフレーズです。クラスの依存関係は、コンストラクター、場合によっては「セッター」メソッドを介してクラスに「注入」されます。
如果我们仔细研究了Service Container我们就会发现laravel的服务容器中只存储了对象的描述,而并不需要知道如何具体的去构造一个对象,因为它会根据php的反射服务去自动解析具体化一个对象。
在计算机科学中,反射是指计算机在运行时(Run time)可以访问、检测和修改它本身状态或行为的一种能力。用来比喻说,那种程序能够“观察”并且修改自己的行为。
支持反射的语言提供了一些在低级语言中难以实现的运行时特性。这些特性包括
PHP实现的反射可以在官网文档中进行查看: 反射API
Example$reflector = new ReflectionClass('App\User');if ($reflector->isInstantiable()) { $user = $refector->newInstance(); //in other case you can send any arguments}
laravel的服务容器的build方法中需要通过反射服务来解析依赖关系,比如说construct函数中需要传递的依赖参数有哪些? 它就需要用到如下方法:
$constructor = $reflector->getConstructor(); // If there are no constructors, that means there are no dependencies then // we can just resolve the instances of the objects right away, without // resolving any other types or dependencies out of these containers. if (is_null($constructor)) { array_pop($this->buildStack); return new $concrete; } $dependencies = $constructor->getParameters();
现在我们应该对laravel如何实现依赖的自动注入有点想法了吧?来整理一下疑问:
你可能会问为什么要问怎么解析依赖?解析依赖肯定是要用到反射的啦,反射,你知道类名不就可以直接解析了吗?
其实。。。不是这样的。。。(@ο@)
很多时候我们为了提高代码的扩展性和维护性,在编写类时依赖的是接口或抽象类,而并不是一个具体的实现类。明白了吗?依赖解析的时候如果只解析到接口或抽象类,然后利用反射,那么这个依赖肯定是错误的。
那么我们就需要在调度系统中注入相关依赖的映射关系,然后在需要的时候正确的解析关系。 比如说, 喂, 我需要一个 A, 你别给我 B 啊。
$container->bind('a', function () { return new B(); // just this for you});$a = $container->make('a');