小編給大家分享一下Laravel—IOC容器是什么,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

成都創(chuàng)新互聯(lián)專注于企業(yè)全網(wǎng)整合營銷推廣、網(wǎng)站重做改版、臨桂網(wǎng)站定制設計、自適應品牌網(wǎng)站建設、H5頁面制作、商城開發(fā)、集團公司官網(wǎng)建設、外貿網(wǎng)站建設、高端網(wǎng)站制作、響應式網(wǎng)頁設計等建站業(yè)務,價格優(yōu)惠性價比高,為臨桂等各大城市提供網(wǎng)站開發(fā)制作服務。
IOC( inversion of controller )叫做控制反轉模式,也可以稱為(dependency injection ) 依賴注入模式。要理解依賴注入的概念我們先理解下什么依賴
//支付寶支付
class Alipay {
public function __construct(){}
public function pay()
{
echo 'pay bill by alipay';
}
}
//微信支付
class Wechatpay {
public function __construct(){}
public function pay()
{
echo 'pay bill by wechatpay';
}
}
//銀聯(lián)支付
class Unionpay{
public function __construct(){}
public function pay()
{
echo 'pay bill by unionpay';
}
}
//支付賬單
class PayBill {
private $payMethod;
public function __construct( )
{
$this->payMethod= new Alipay ();
}
public function payMyBill()
{
$this->payMethod->pay();
}
}
$pb = new PayBill ();
$pb->payMyBill();通過上面的代碼我們知道,當我們創(chuàng)建一個class PayBill 的實例的時候, PayBill的構造函數(shù)里面有{ $this->payMethod= new Alipay (); }, 也就是實例化了一個class Alipay . 這個時候依賴就產(chǎn)生了, 這里可以理解為當我想用支付寶支付的時候, 那我首先要獲取到一個支付寶的實例,或者理解為獲取支付寶的功能支持. 當用我們完 new 關鍵字的時候, 依賴其實已經(jīng)解決了,因為我們獲取了Alipay 的實例.
其實在我知道ioc概念之前,我的代碼中大部分都是這種模式 ~ _ ~ . 這種有什么問題呢, 簡單來說, 比如當我想用的不是支付寶而是微信的時候怎么辦, 你能做的就是修改Payment 的構造函數(shù)的代碼,實例化一個微信支付Wechatpay.
如果我們的程序不是很大的時候可能還感覺不出什么,但是當你的代碼非常復雜,龐大的時候,如果我們的需求經(jīng)常改變,那么修改代碼就變的非常麻煩了。所以ioc 的思想就是不要在 class Payment 里面用new 的方式去實例化解決依賴, 而且轉為由外部來負責,簡單一點就是內部沒有new 的這個步驟,通過依賴注入的方式同樣的能獲取到支付的實例.
依賴我們知道了是什么意思,那依賴注入又是什么意思呢,我們把上面的代碼拓展一下
//支付類接口
interface Pay
{
public function pay();
}
//支付寶支付
class Alipay implements Pay {
public function __construct(){}
public function pay()
{
echo 'pay bill by alipay';
}
}
//微信支付
class Wechatpay implements Pay {
public function __construct(){}
public function pay()
{
echo 'pay bill by wechatpay';
}
}
//銀聯(lián)支付
class Unionpay implements Pay {
public function __construct(){}
public function pay()
{
echo 'pay bill by unionpay';
}
}
//付款
class PayBill {
private $payMethod;
public function __construct( Pay $payMethod)
{
$this->payMethod= $payMethod;
}
public function payMyBill()
{
$this->payMethod->pay();
}
}
//生成依賴
$payMethod = new Alipay();
//注入依賴
$pb = new PayBill( $payMethod );
$pb->payMyBill();上面的代碼中,跟之前的比較的話,我們加入一個Pay 接口, 然后所有的支付方式都繼承了這個接口并且實現(xiàn)了pay 這個功能. 可能大家會問為什么要用接口,這個我們稍后會講到.
當我們實例化PayBill的之前, 我們首先是實例化了一個Alipay,這個步驟就是生成了依賴了,然后我們需要把這個依賴注入到PayBill 的實例當中,通過代碼我們可以看到 { $pb = new PayBill( payMethod ); }, 我們是通過了構造函數(shù)把這個依賴注入了PayBill 里面. 這樣一來 $pb 這個PayBill 的實例就有了支付寶支付的能力了.
把class Alipay 的實例通過constructor注入的方式去實例化一個 class PayBill. 在這里我們的注入是手動注入, 不是自動的. 而Laravel 框架實現(xiàn)則是自動注入.
在介紹IOC 的容器之前我們先來理解下反射的概念(reflection),因為IOC 容器也是要通過反射來實現(xiàn)的.從網(wǎng)上抄了一段來解釋反射是什么意思
“反射它指在PHP運行狀態(tài)中,擴展分析PHP程序,導出或提取出關于類、方法、屬性、參數(shù)等的詳細信息,包括注釋。這種動態(tài)獲取的信息以及動態(tài)調用對象的方法的功能稱為反射API。反射是操縱面向對象范型中元模型的API,其功能十分強大,可幫助我們構建復雜,可擴展的應用。其用途如:自動加載插件,自動生成文檔,甚至可用來擴充PHP語言”
舉個簡單的例子
class B{
}
class A {
public function __construct(B $args)
{
}
public function dosomething()
{
echo 'Hello world';
}
}
//建立class A 的反射
$reflection = new ReflectionClass('A');
$b = new B();
//獲取class A 的實例
$instance = $reflection ->newInstanceArgs( [ $b ]);
$instance->dosomething(); //輸出 ‘Hellow World’
$constructor = $reflection->getConstructor();//獲取class A 的構造函數(shù)
$dependencies = $constructor->getParameters();//獲取class A 的依賴類
dump($constructor);
dump($dependencies);dump 的得到的$constructor 和 $dependencies 結果如下
//constructor
ReflectionMethod {#351
+name: "__construct"
+class: "A"
parameters: array:1 []
extra: array:3 []
modifiers: "public"
}
//$dependencies
array:1 [
0 => ReflectionParameter {#352
+name: "args"
position: 0
typeHint: "B"
}
]通過上面的代碼我們可以獲取到 class A 的構造函數(shù),還有構造函數(shù)依賴的類,這個地方我們依賴一個名字為 ‘a(chǎn)rgs’ 的量,而且通過TypeHint可以知道他是類型為 Class B; 反射機制可以讓我去解析一個類,能過獲取一個類里面的屬性,方法 ,構造函數(shù), 構造函數(shù)需要的參數(shù)。 有個了這個才能實現(xiàn)Laravel 的IOC 容器.
接下來介紹一下Laravel 的IOC服務容器概念. 在laravel框架中, 服務容器是整個laravel的核心,它提供了整個系統(tǒng)功能及服務的配置, 調用. 容器按照字面上的理解就是裝東西的東西,比如冰箱, 當我們需要冰箱里面的東西的時候直接從里面拿就行了. 服務容器也可以這樣理解, 當程序開始運行的時候,我們把我們需要的一些服務放到或者注冊到(bind)到容器里面,當我需要的時候直接取出來(make)就行了. 上面提到的 bind 和 make 就是注冊 和 取出的 兩個動作.
好了,說了這么多,下面要上一段容器的代碼了. 下面這段代碼不是laravel 的源碼, 而是來自一本書《laravel 框架關鍵技術解析》. 這段代碼很好的還原了laravel 的服務容器的核心思想. 代碼有點長, 小伙伴們要耐心看. 當然小伙伴完全可以試著運行一下這段代碼,然后調試一下,這樣會更有助于理解.
<?php
//容器類裝實例或提供實例的回調函數(shù)
class Container {
//用于裝提供實例的回調函數(shù),真正的容器還會裝實例等其他內容
//從而實現(xiàn)單例等高級功能
protected $bindings = [];
//綁定接口和生成相應實例的回調函數(shù)
public function bind($abstract, $concrete=null, $shared=false) {
//如果提供的參數(shù)不是回調函數(shù),則產(chǎn)生默認的回調函數(shù)
if(!$concrete instanceof Closure) {
$concrete = $this->getClosure($abstract, $concrete);
}
$this->bindings[$abstract] = compact('concrete', 'shared');
}
//默認生成實例的回調函數(shù)
protected function getClosure($abstract, $concrete) {
return function($c) use ($abstract, $concrete) {
$method = ($abstract == $concrete) ? 'build' : 'make';
return $c->$method($concrete);
};
}
public function make($abstract) {
$concrete = $this->getConcrete($abstract);
if($this->isBuildable($concrete, $abstract)) {
$object = $this->build($concrete);
} else {
$object = $this->make($concrete);
}
return $object;
}
protected function isBuildable($concrete, $abstract) {
return $concrete === $abstract || $concrete instanceof Closure;
}
//獲取綁定的回調函數(shù)
protected function getConcrete($abstract) {
if(!isset($this->bindings[$abstract])) {
return $abstract;
}
return $this->bindings[$abstract]['concrete'];
}
//實例化對象
public function build($concrete) {
if($concrete instanceof Closure) {
return $concrete($this);
}
$reflector = new ReflectionClass($concrete);
if(!$reflector->isInstantiable()) {
echo $message = "Target [$concrete] is not instantiable";
}
$constructor = $reflector->getConstructor();
if(is_null($constructor)) {
return new $concrete;
}
$dependencies = $constructor->getParameters();
$instances = $this->getDependencies($dependencies);
return $reflector->newInstanceArgs($instances);
}
//解決通過反射機制實例化對象時的依賴
protected function getDependencies($parameters) {
$dependencies = [];
foreach($parameters as $parameter) {
$dependency = $parameter->getClass();
if(is_null($dependency)) {
$dependencies[] = NULL;
} else {
$dependencies[] = $this->resolveClass($parameter);
}
}
return (array)$dependencies;
}
protected function resolveClass(ReflectionParameter $parameter) {
return $this->make($parameter->getClass()->name);
}
}上面的代碼就生成了一個容器,下面是如何使用容器
$app = new Container();
$app->bind("Pay", "Alipay");//Pay 為接口, Alipay 是 class Alipay
$app->bind("tryToPayMyBill", "PayBill"); //tryToPayMyBill可以當做是Class PayBill 的服務別名
//通過字符解析,或得到了Class PayBill 的實例
$paybill = $app->make("tryToPayMyBill");
//因為之前已經(jīng)把Pay 接口綁定為了 Alipay,所以調用pay 方法的話會顯示 'pay bill by alipay '
$paybill->payMyBill();當我們實例化一個Container得到 $app 后, 我們就可以向其中填充東西了
$app->bind("Pay", "Alipay");
$app->bind("tryToPayMyBill", "PayBill");當執(zhí)行完這兩行綁定碼后, $app 里面的屬性 $bindings 就已經(jīng)有了array 值,是啥樣的呢,我們來看下
array:2 [
"App\Http\Controllers\Pay" => array:2 [
"concrete" => Closure {#355
class: "App\Http\Controllers\Container"
this:Container{[#354](http://127.0.0.4/ioc#sf-dump-254248394-ref2354) …}
parameters: array:1 [
"$c" => []
]
use: array:2 [
"$abstract" => "App\Http\Controllers\Pay"
"$concrete" => "App\Http\Controllers\Alipay"
]
file: "C:\project\test\app\Http\Controllers\IOCController.php" line: "119 to 122"
}
"shared" => false
]
"tryToPayMyBill" => array:2 [
"concrete" => Closure {#359
class: "App\Http\Controllers\Container"
this:Container{[#354](http://127.0.0.4/ioc#sf-dump-254248394-ref2354) …}
parameters: array:1 [
"$c" => []
]
use: array:2 [
"$abstract" => "tryToPayMyBill"
"$concrete" => "\App\Http\Controllers\PayBill"
]
file: "C:\project\test\app\Http\Controllers\IOCController.php" line: "119 to 122"
}
"shared" => false
]
]當執(zhí)行 $paybill = $app->make(“tryToPayMyBill”); 的時候, 程序就會用make方法通過閉包函數(shù)的回調開始解析了.
解析’tryToPayBill’ 這個字符串, 程序通過閉包函數(shù) 和build方法會得到 ‘PayBill’ 這個字符串,該字符串保存在$concrete 上. 這個是第一步. 然后程序還會以類似于遞歸方式 將$concrete 傳入 build() 方法. 這個時候build里面就獲取了$concrete = ‘PayBill’. 這個時候反射就派上了用場, 大家有沒有發(fā)現(xiàn),PayBill 不就是 class PayBill 嗎? 然后在通過反射的方法ReflectionClass(‘PayBill’) 獲取PayBill 的實例. 之后通過getConstructor(),和getParameters() 等方法知道了 Class PayBill 和 接口Pay 存在依賴
//$constructor = $reflector->getConstructor();
ReflectionMethod {#374
+name: "__construct"
+class: "App\Http\Controllers\PayBill"
parameters: array:1 [
"$payMethod" => ReflectionParameter {#371
+name: "payMethod"
position: 0 typeHint: "App\Http\Controllers\Pay"
}
]
extra: array:3 [
"file" => "C:\project\test\app\Http\Controllers\IOCController.php"
"line" => "83 to 86"
"isUserDefined" => true
]
modifiers: "public"
}
//$dependencies = $constructor->getParameters();
array:1 [
0 => ReflectionParameter {#370
+name: "payMethod"
position: 0
typeHint: "App\Http\Controllers\Pay"
}
]接著,我們知道了有’Pay’這個依賴之后呢,我們要做的就是解決這個依賴,通過 getDependencies($parameters), 和 resolveClass(ReflectionParameter $parameter) ,還有之前的綁定$app->bind(“Pay”, “Alipay”); 在build 一次的時候,通過 return new $concrete;到這里我們得到了這個Alipay 的實例
if(is_null($constructor)) {
return new $concrete;
}到這里我們總算結局了這個依賴, 這個依賴的結果就是實例化了一個 Alipay. 到這里還沒結束
$instances = $this->getDependencies($dependencies);
上面的$instances 數(shù)組只有一個element 那就是 Alipay 實例
array:1 [0 =>Alipay
{#380}
]最終通過 newInstanceArgs() 方法, 我們獲取到了 PayBill 的實例。
return $reflector->newInstanceArgs($instances);
到這里整個流程就結束了, 我們通過 bind 方式綁定了一些依賴關系, 然后通過make 方法 獲取到到我們想要的實例. 在make中有牽扯到了閉包函數(shù),反射等概念.
好了,當我們把容器的概念理解了之后,我們就可以理解下為什么要用接口這個問題了. 如果說我不想用支付寶支付,我要用微信支付怎么辦,too easy.
$app->bind("Pay", "Wechatpay");
$app->bind("tryToPayMyBill", "PayBill");
$paybill = $app->make("tryToPayMyBill");
$paybill->payMyBill();是不是很簡單呢, 只要把綁定從’Alipay’ 改成 ‘Wechatpay’ 就行了,其他的都不用改. 這就是為什么我們要用接口. 只要你的支付方式繼承了pay 這個接口,并且實現(xiàn)pay 這個方法,我們就能夠通過綁定正常的使用. 這樣我們的程序就非常容易被拓展,因為以后可能會出現(xiàn)成百上千種的支付方式.
好了,到這里不知道小伙伴有沒有理解呢,我建議大家可以試著運行下這些代碼, 這樣理解起來會更快.同時推薦大家去看看 《laravel 框架關鍵技術解析》這本書,寫的還是不錯的.
以上是“Laravel—IOC容器是什么”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注創(chuàng)新互聯(lián)行業(yè)資訊頻道!
新聞標題:Laravel—IOC容器是什么
瀏覽路徑:http://chinadenli.net/article20/jiigco.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供移動網(wǎng)站建設、小程序開發(fā)、網(wǎng)站維護、營銷型網(wǎng)站建設、微信小程序、服務器托管
聲明:本網(wǎng)站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)