中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

php依賴注入

發布時間:2020-07-25 10:29:52 來源:網絡 閱讀:1222 作者:china_lx1 欄目:開發技術

在軟件工程領域,依賴注入(Dependency Injection)是用于實現控制反轉(Inversion of Control)的最常見的方式之一。本文主要介紹依賴注入原理和常見的實現方式,重點在于介紹這種年輕的設計模式的適用場景及優勢。


首先我們來一個實例,上代碼

<?php

class A
{
	public function test()
	{
		echo 'this is A!<br>';
		$b = new B();
		$b->test();
	}
}

class B
{
	public function test()
	{
		echo 'this is B!<br>';
		$c = new C();
		$c->test();
	}
}

class C
{
	public function test()
	{
		echo 'this is C!<br>';
	}
}

$obj = new A();

$obj->test();


結果是:

this is A!
this is B!
this is C!


從代碼分析,A類依賴B類,B類依賴C類。這是我們最原始的實現思路.這種實現思路很明顯會有問題

假如我們現在B類修改下,代碼如下:

class B
{

	public $name;

	public function __construct($name)
	{
		$this->name = $name;
	}

	public function test()
	{
		echo 'this is B'.$this->name.'!<br>';
		$c = new C();
		$c->test();
	}
}


此時再看我們原來A類test方法直接調用明顯會有問題,于是此時我們需要將原來代碼:

class A
{
	public function test()
	{
		echo 'this is A!<br>';
		$b = new B();
		$b->test();
	}
}

修改成:

class A
{
	public function test()
	{
		echo 'this is A!<br>';
		$b = new B('(class B)');//構造的時候多加了一個參數
		$b->test();
	}
}

如果此時C類構造方法也變動了呢,B的方法里面也同樣受影響,很明顯可用性非常低


為了解耦,此時我們用到第二種思路:構造器注入,直接上代碼:

<?php

class A
{
	public $obj;

	public function __construct(B $b)
	{
		$this->obj = $b;
	}

	public function test()
	{
		echo 'this is A!<br>';
		$this->obj->test();
	}
}

class B
{
	public $obj;
	public function __construct(C $c)
	{
		$this->obj = $c;
	}

	public function test()
	{
		echo 'this is B!<br>';
		$this->obj->test();
	}
}

class C
{
	public function test()
	{
		echo 'this is C!<br>';
	}
}
$c = new C();
$b = new B($c);
$obj = new A($b);
$obj->test();

這種方法可以解決第一種方法,如果依賴的類構造方法(比如B類)有所改動,A類不需要改動任何代碼。但是久而久之,這種方法毛病也出來了,我們首先必須要先實例化C類,再實例化B類,最后再實例化A類。


了解到第二種方案需要優化,于是出現了基本成型的第三種方案,此時我們用到了container(容器)和instance(實例),直接上代碼:

class Container
{

	public static $_definations = [];
	
	
	public function get($class)
	{

		//當前類所依賴的類
		$depends = [];
		
		$tc = new ReflectionClass($class);
		//得到構造方法
		$constructor = $tc->getConstructor();

		//得到構造方法的參數
		if($constructor !== NULL)
		{
			foreach($constructor->getParameters() as $parameter)
			{
				if($parameter->isDefaultValueAvailable())
				{
					$depends[] = $parameter->getDefaultValue();
				}
				else
				{
					$pc = $parameter->getClass();
					$instance = Instance::getInstance($pc == NULL ? NULL : $pc->getName());
					$depends[] = $instance;
				}
			}
		}

		foreach($depends as $k => $v)
		{
			if($v instanceof Instance)
			{
				if($v->id !== NULL)
				{
					$depends[$k] = $this->get($v->id);
				}
			}
		}

		$tm_instance = $tc->newInstanceArgs($depends);
		return $tm_instance;
	}
}

class Instance{
	/**
	 * @var 類唯一標示
	 */
	public $id;

	/**
	 * 構造函數
	 * @param string $id 類唯一ID
	 * @return void
	 */
	public function __construct($id)
	{
		$this->id = $id;
	}

	/**
	 * 獲取類的實例
	 * @param string $id 類唯一ID
	 * @return Object Instance
	 */
	public static function getInstance($id)
	{
		return new self($id);
	}
}

class Base{
	
}

class A extends Base{
	private $instanceB;

	public function __construct(B $instanceB)
	{
		$this->instanceB = $instanceB;
	}

	public function test()
	{
		echo 'this is A!<br/>';
		$this->instanceB->test();
	}
}


class B  extends Base{
	private $instanceC;

	public function __construct(C $instanceC)
	{
		$this->instanceC = $instanceC;
	}

	public function test()
	{
		echo 'this is B!<br/>';
		return $this->instanceC->test();
	}
}

class C  extends Base{
	public function test()
	{
		echo 'this is C!';
	}
}


$container = new Container();

$obj_a = $container->get('A');

$obj_a->test();

此方法有參考yii2中yii2\di\container實現,只是將它簡化了,更容易看懂。重點看看container的get方法


現在我們增加set方法,自定義函數,直接上代碼精簡版

class Container
{
	/**
	*@var array 存儲各個類的定義  以類的名稱為鍵
	*/
	public static $_definations = [];

	
	public function get($class, $params = [], $props = [])
	{
		if(!isset(self::$_definations[$class]))
			return $this->build($class, $params, $props);

		//如果已經被定義過的
		$_defination = self::$_definations[$class];
		
		if(is_callable($_defination, true))
		{
			return call_user_func($_defination, $this, $params, $props);
		}
		else if(is_object($_defination))
		{
			return $_defination;
		}
		else
		{
			throw new Exception($class . '聲明錯誤');
		}
	}

	public function set($class, $_defination)
	{
		self::$_definations[$class] = $_defination;
		
	}

	public function build($class, $params, $props)
	{
		//當前類所依賴的類
		$depends = [];
		
		$tc = new ReflectionClass($class);
		//得到構造方法
		$constructor = $tc->getConstructor();

		//得到構造方法的參數
		if($constructor !== NULL)
		{
			foreach($constructor->getParameters() as $parameter)
			{
				if($parameter->isDefaultValueAvailable())
				{
					$depends[] = $parameter->getDefaultValue();
				}
				else
				{
					$pc = $parameter->getClass();
					$instance = Instance::getInstance($pc == NULL ? NULL : $pc->getName());
					$depends[] = $instance;
				}
			}
		}

		foreach($depends as $k => $v)
		{
			if($v instanceof Instance)
			{
				if($v->id !== NULL)
				{
					$depends[$k] = $this->get($v->id);
				}
			}
		}

		$tm_instance = $tc->newInstanceArgs($depends);
		return $tm_instance;
	}
}


增加了一個set方法,并將get方法稍微改版了一下,現在我們看看怎么調用set方法:

$container = new Container();

$container->set('foo', function($container, $params, $config){
	print_r($params);
	print_r($config);
});

$container->get('foo', ['p1' => 'pv1'], ['c1' => 'cv1']);


輸出結果為:

Array ( [p1] => pv1 ) Array ( [c1] => cv1 )


再看看另外一種情況調用:

class Test
{
    public function mytest()
    {
        echo 'this is a test';
    }
}

$container->set('testObj', new Test());

$test = $container->get('testObj');
$test->mytest();


輸出結果為:

this is a test


上面的代碼只是作者粗略的寫了下簡單版本,很多地方不是太完善,這版本是為了理解yii2的container打下基礎,稍后會出yii2的依賴注入源碼分析

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

图片| 潢川县| 尼勒克县| 青川县| 阿克陶县| 昌黎县| 伊吾县| 临泉县| 德江县| 靖安县| 密山市| 肥西县| 靖边县| 长汀县| 大英县| 台东市| 泉州市| 潼南县| 河曲县| 郁南县| 府谷县| 聂拉木县| 伊金霍洛旗| 宜城市| 宁夏| 巴青县| 阳西县| 兴业县| 新余市| 融水| 江北区| 保山市| 章丘市| 池州市| 清水县| 湖南省| 蕲春县| 冀州市| 炎陵县| 淅川县| 迁西县|