本文目錄一覽:
- 1、php IOC容器的理解
- 2、php function括弧里(類名 變數名)這種寫法是什麼意思?
- 3、怎麼能通俗易通的了解php中的反射和依賴注入這兩個概念
- 4、spring中的依賴注入有什麼用?
- 5、php依賴注入是在構造函數中注入嗎
- 6、php怎麼實例化有依賴注入的類
php IOC容器的理解
依賴注入是指一個類必須依賴另一個實例才能進行實例化。
進一步利用介面
升華-IOC容器
使用示例
php function括弧里(類名 變數名)這種寫法是什麼意思?
php本來是弱類型語言,經過這幾年的發展,php也支持了類型判斷,比如可以聲明一個函數變數為
function test(int $a):int{}
對於類名,變數名這種寫法,是php5中引入的,這樣目的就是對參數進行限定,可以提前判斷出不符合類型的變數傳入。
依賴注入是一種設計模式,而它依賴的就是這個功能,通過注入不同的類來實現不同的功能。
怎麼能通俗易通的了解php中的反射和依賴注入這兩個概念
所謂反射是動態獲取類信息,還能做出修改。比如一些魔術方法 __FUNCTION__,__METHOD__。進階一點可以使用 reflectionClass,就是反射類獲取。
你可以去後盾人平台看看,裡面的東西不錯
spring中的依賴注入有什麼用?
依賴注入是spring的的兩大核心之一,也叫控制反轉,他的作用是將創建對象的管理交給spring容器,以前寫項目會用new people的方式來創建一個people類,現在用了spring後,可以在xml中配置,也可以用註解的方式,在class文件開始部分寫下面的代碼,然後在這個class文件中使用到people就可以直接用people,而不需要用new來創建了,這樣也大大降低了耦合性,
數據的確還是前台傳到controller里,但是你在寫controller的時候是不是可以通過註解的方式創建類,而不需要new了呢?或者在調用service方法的時候,不需要再new service類了,而是直接通過註解的方式在文件頭聲明下,後面就 直接使用了呢?
@Resources
private People people;
php依賴注入是在構造函數中注入嗎
PHP 依賴注入
tags: dependency injection,php
by Ryan on January 8, 2009
Dependency injection is the answer to more maintainable, testable, modular code.
依賴注入是對於要求更易維護,更易測試,更加模塊化的代碼的答案。
Every project has dependencies and the more complex the project is the more dependencies it will most likely have. The most common dependency in today』s web application is the database and chances are if it goes down the app will all together stop working. That is because the code is dependent on the database server… and that is perfectly fine. Not using a database server because it could one day crash is a bit ridiculous. Even though the dependency has its flaws, it still makes life for the code, and thus the developer, a lot easier.
每個項目都有依賴(外界提供的輸入), 項目越複雜,越需要更多的依賴。在現今的網路應用程序中,最常見的依賴是資料庫,其風險在於,一旦資料庫暫停運行,那麼整個程序也因此而停止運行。這是因為代碼依賴資料庫伺服器。。。這已足夠。因為資料庫伺服器有時會崩潰而棄用它是荒謬的。儘管依賴有其自身的瑕疵,它仍然使代碼,因而也使程序開發人員的生活更容易些。
The problem with most dependencies its the way that code handles and interacts with them, meaning, the problem is the code and not the dependency. If you are not using dependency injection, chances are your code looks something like this:
對於大多依賴而言,問題在於代碼如何處理它們及與它們交往。也就是說,問題是代碼本身而非依賴。如果你沒有使用依賴注入,有機會遇到下列代碼:
class Book {
publicfunction __construct(){
$registry = RegistrySingleton::getInstance();
$this-_databaseConnection=$registry-databaseConnection;
// or
global$databaseConnection;
$this-_databaseConnection=$databaseConnection;
}
}
The book object now is given full access to the database once it is constructed. That is good, the book needs to be able to talk to the database and pull data. The problem lies in the way the book gained its access. In order for the book to be able to talk to the database the code must have an outside variable named $databaseConnection, or worse, it must have a singleton pattern class (registry) object containing a record for a databaseConnection. If these don』t exist the book fails, making this code is far from modular.
現在對象book一旦建立,就已經完全連到資料庫。這沒什麼不好,book需要跟資料庫交談並取得數據。問題在於book取得其接入的方法。要使book能夠與資料庫交談,代碼必須有一個外來的變數$databaseConnect, 更糟糕的是,它必須有個singleton類型類(registry)的對象,其包含一個databaseConnection的記錄。如果這些不存在的話,book會無法運行,這就使得這些代碼遠遠不夠模塊化。
This raises the question, how exactly does the book get access to the database? This is where inversion of control comes in.
這就提出一個問題,到底book如何接入資料庫?這就是IoC出現的原因了。
In Hollywood a struggling actor does not call up Martin Scorsese and ask for a role in his next film. No, the opposite happens. Martin Scorsese calls up the broke actor and asks him to play the main character in his next movie. Objects are struggling actors, they do not get to pick the roles they play, the director needs to tell them what to do. Objects do not get to pick the outside systems they interact with, instead, the outside systems are given to the objects. Remember this as Inversion of Control: The Hollywood Way.
在好萊塢,一個瀕臨絕境的演員不會打電話給Martin Scoresese要求在他的下個影片中扮演一個角色。絕不會這樣,實際正相反。Martin Scorese 會打電話給這個困頓的演員並邀請他在下一部影片中扮演重要的角色。對象是掙扎中的演員,他們不會去撿自己所扮演的角色,導演需要告訴他們去做什麼。對象不會到它所接觸的外界挑選系統,相反,外界系統會被賦予對象。記住這就是IoC( Inversion of Control):好萊塢的做法。
This is how a developer tells his objects how to interact with outside dependencies:
如下是開發人員告訴他的對象如何與外界的依賴打交道:
class Book {
publicfunction __construct(){}
publicfunction setDatabaseConnection($databaseConnection){
$this-_databaseConnection=$databaseConnection;
}
}
$book=new Book();
$book-setDatabase($databaseConnection);
This code allows for the book class to be used in any web app. The Book is no longer dependent on anything other than the developer supplying a database shortly after object creation.這代碼允許這個book類能在任何的網頁程序中使用。此book不再依賴任何事項,除了程序開發者要在對象創建後立即要提供一個資料庫。
This is, at its finest, dependency injection. There are two common practices of injecting dependencies. The first being constructor injection and the second being setter injection. Constructor injection involves passing all of the dependencies as arguments when creating a new object. The code would look something like this:
這就是最佳方法—依賴注入。有兩種常用的依賴注入的方式。一種是 constructor (註:構造函數。這種譯法似乎並不恰當,類中此方法更多是用來對某些屬性進行初始化)注入,一種是setter 注入。Constructor注入涉及到將所有依賴作為參數,傳遞給新創建的對象。看起來像這樣:
$book=new Book($databaseConnection,$configFile);
The more dependencies an object has, the messier this construction becomes. There are other reasons why this is a bad approach, involving ideas around code reusability and constructors doing work.
對象的依賴越多,construction就會變得越雜亂。這裡還有其他的原因為什麼這是一個壞方法,其涉及到包括代碼重用和constructors要做的工作。
This leaves us with other method of dependency injection, called setting injection, which involves creating a public method inside the object for the dependencies that need injection.
這就給我們留下其他的方法進行依賴注入,稱為設置注入,包含在需要注入依賴的對象里創建一個公共方法:
$book=new Book();
$book-setDatabase($databaseConnection);
$book-setConfigFile($configFile);
This is easy to follow, but it leads writing more and more code for your application. When a book object is created three lines of code are required. If we have to inject another dependency, a 4th line of code is now needed. This gets messy quickly.
這很容易實現,但是它會導致為您的程序寫大量代碼。當創建一個book對象時,需要三行代碼。如果我們必須注入另外的依賴時,必須增加第四行代碼。這很快變得一團糟。
The answer to this problem is a factory, which is class that is designed to create and then inject all the dependencies needed for an object. Here is an example:
此問題的對策是一個工廠factory,它是一個類,用來創建然後注入一個對象的所有依賴。舉例如下:
class Factory {
public static $_database;
public static function makeBook(){
$book=new Book();
$book-setDatabase(self::$_database);
// more injection…(更多注入)
return$book;
}
}
And then:
然後:
$book= Factory::makeBook();
All dependencies should be registered into the factory object during run time. This object is now the gateway that all dependencies must pass through before they can interact with any classes. In other words, this is the dependency container.
所有的依賴在運行期間都應在此factory對象中註冊。它現在是大門,在依賴可以與任何對象打交道前,都必經此門。
The reason makeBook is a public static function is for ease of use and global access. When I started this article off I made a reference to the singleton pattern and global access being a poor choices of code. They are… for the most part. It is bad design when they control access, but it is perfectly ok when they control creation. The makeBook function is only a shortcut for creation. There is no dependency what-so-ever between the book class and the factory class. The factory class exists so we can contain our dependencies in one location and automatically inject those dependencies with one line of code creation.
makeBook作為一個靜態方法的原因是易用並且可以在全局得到。在本文開頭,我提出使用singleton類型和全局變數對代碼而言是一個糟糕的選擇。多數情形下,確實如此!當他們控制接入時,是一個差設計。但是在他們控制創建時,是一個不錯的選擇。makeBook方法僅僅是創建的一個捷徑。在book類和factory類之間,沒有任何依賴。由於factory類的存在,我們的依賴可以存放在一個地點,並且用一行創建代碼就可自動注入這些依賴。
The factory or container class removes all of the extra work of dependency injection.
此處的factory或者容器類移走了依賴注入的所有額外工作。
Before injection:
以前的注入:
$book=new Book();
And now:
目前的方法:
$book= Factory::makeBook();
Hardly any extra work, but tons of extra benefits.
幾乎沒有任何的額外工作,但是有大量益處。
When test code is run, specifically unit tests, the goal is to see if a method of a class is working correctly. Since the book class requires database access to read the book data it adds a whole layer of complexity. The test has to acquire a database connection, pull data, and test it. All of a sudden the test is no longer testing a single method in the book class, it is now also testing database. If the database is offline, the test would fail. This is FAR from the goal a unit test.當運行測試代碼時,尤其是單元測試,其目標是檢查類中的方法是否正確地工作。由於book類要求接入資料庫並且讀取圖書數據,它增加了一層複雜度。此測試不得不進行資料庫連接,取得數據,然後測試它。瞬間,測試不再是測試book類中的單個方法,它目前同時也測試資料庫。如果資料庫離線,測試就會失敗。這已經遠離了單元測試的目的。
A way of dealing with this is just using a different database dependency for the unit tests. When the test suite starts up a dummy database is injected into the book. The dummy database will always have the data the developer expects it to have. If a live database was used in a unit test the data could potentially change causing tests to unnecessarily fail. There is no need for a unit test to be refactored when a record in a database changes.
解決上述問題的方法是用不同的資料庫依賴來作單元測試。當測試套件開始時,虛擬的資料庫被注入book.虛擬資料庫將永遠擁有開發人員所期待的數據。如果使用一個真實資料庫,數據的潛在變化會導致測試不必要的失敗。當資料庫的記錄改變了,不需因此重新進行單元測試。
The code is more modular because it can dropped into any other web application. Create the book object and inject a database connection with $book-setDatabase(). It does not matter if the database is in Registery::Database, $database, or $someRandomDatabaseVarible. As long as there is a database connection the book will work inside any system.
此代碼現在更加模塊化,因為它可以被放到任何其他的網頁程序。創建book對象並且用$book-setDatabase()注入資料庫連接。此時,資料庫在 Registery::Database, $database,或者$someRandomDatabaseVarible都無關大局。只要有一個資料庫連接,book就可以在任何系統內工作。
The code is more maintainable because each object given exactly what it needs. If separate database connections are required between different instances of the same class then there no extra code needed inside the class what-so-ever. Give book1 access to database1 and book2 access to database2.
代碼更加易維護,因為每個對象都被賦予了它的所需。如果同一類的實例需要不同的資料庫連接,在類內部一點兒也不需要額外的代碼。例如book1連接到資料庫1,book2連接到資料庫2
Factory::$_database=$ourDatabaseVarForDB1;
$book1= Factory::makeBook();
$book2= Factory::makeBook();
$book2-setDatabase($database2);
Dependency injection really is the answer to more maintainable, testable, modular code.
依賴注入真的是更易維護,更易測試和更加模塊化的答案。
php怎麼實例化有依賴注入的類
PHP依賴注入的理解。分享給大家供大家參考,具體如下:
看Laravel的IoC容器文檔只是介紹實例,但是沒有說原理,之前用MVC框架都沒有在意這個概念,無意中在phalcon的文檔中看到這個詳細的介紹,感覺豁然開朗,複製粘貼過來,主要是好久沒有寫東西了,現在確實很懶變得!
首先,我們假設,我們要開發一個組件命名為SomeComponent。這個組件中現在將要注入一個資料庫連接。
在這個例子中,資料庫連接在component中被創建,這種方法是不切實際的,這樣做的話,我們將不能改變資料庫連接參數及資料庫類型等一些參數。
class SomeComponent {
/**
* The instantiation of the connection is hardcoded inside
* the component so is difficult to replace it externally
* or change its behavior
*/
public function someDbTask()
{
$connection = new Connection(array(
“host” = “localhost”,
“username” = “root”,
“password” = “secret”,
“dbname” = “invo”
));
// …
}
}
$some = new SomeComponent();
$some-someDbTask();
為了解決上面所說的問題,我們需要在使用前創建一個外部連接,並注入到容器中。就目前而言,這看起來是一個很好的解決方案:
class SomeComponent {
protected $_connection;
/**
* Sets the connection externally
*/
public function setConnection($connection)
{
$this-_connection = $connection;
}
public function someDbTask()
{
$connection = $this-_connection;
// …
}
}
$some = new SomeComponent();
//Create the connection
$connection = new Connection(array(
“host” = “localhost”,
“username” = “root”,
“password” = “secret”,
“dbname” = “invo”
));
//Inject the connection in the component
$some-setConnection($connection);
$some-someDbTask();
現在我們來考慮一個問題,我們在應用程序中的不同地方使用此組件,將多次創建資料庫連接。使用一種類似全局註冊表的方式,從這獲得一個資料庫連接實例,而不是使用一次就創建一次。
class Registry
{
/**
* Returns the connection
*/
public static function getConnection()
{
return new Connection(array(
“host” = “localhost”,
“username” = “root”,
“password” = “secret”,
“dbname” = “invo”
));
}
}
class SomeComponent
{
protected $_connection;
/**
* Sets the connection externally
*/
public function setConnection($connection){
$this-_connection = $connection;
}
public function someDbTask()
{
$connection = $this-_connection;
// …
}
}
$some = new SomeComponent();
//Pass the connection defined in the registry
$some-setConnection(Registry::getConnection());
$some-someDbTask();
現在,讓我們來想像一下,我們必須在組件中實現兩個方法,首先需要創建一個新的資料庫連接,第二個總是獲得一個共享連接:
class Registry
{
protected static $_connection;
/**
* Creates a connection
*/
protected static function _createConnection()
{
return new Connection(array(
“host” = “localhost”,
“username” = “root”,
“password” = “secret”,
“dbname” = “invo”
));
}
/**
* Creates a connection only once and returns it
*/
public static function getSharedConnection()
{
if (self::$_connection===null){
$connection = self::_createConnection();
self::$_connection = $connection;
}
return self::$_connection;
}
/**
* Always returns a new connection
*/
public static function getNewConnection()
{
return self::_createConnection();
}
}
class SomeComponent
{
protected $_connection;
/**
* Sets the connection externally
*/
public function setConnection($connection){
$this-_connection = $connection;
}
/**
* This method always needs the shared connection
*/
public function someDbTask()
{
$connection = $this-_connection;
// …
}
/**
* This method always needs a new connection
*/
public function someOtherDbTask($connection)
{
}
}
$some = new SomeComponent();
//This injects the shared connection
$some-setConnection(Registry::getSharedConnection());
$some-someDbTask();
//Here, we always pass a new connection as parameter
$some-someOtherDbTask(Registry::getConnection());
到此為止,我們已經看到了如何使用依賴注入解決我們的問題。不是在代碼內部創建依賴關係,而是讓其作為一個參數傳遞,這使得我們的程序更容易維護,降低程序代碼的耦合度,實現一種松耦合。但是從長遠來看,這種形式的依賴注入也有一些缺點。
例如,如果組件中有較多的依賴關係,我們需要創建多個setter方法傳遞,或創建構造函數進行傳遞。另外,每次使用組件時,都需要創建依賴組件,使代碼維護不太易,我們編寫的代碼可能像這樣:
//Create the dependencies or retrieve them from the registry
$connection = new Connection();
$session = new Session();
$fileSystem = new FileSystem();
$filter = new Filter();
$selector = new Selector();
//Pass them as constructor parameters
$some = new SomeComponent($connection, $session, $fileSystem, $filter, $selector);
// … or using setters
$some-setConnection($connection);
$some-setSession($session);
$some-setFileSystem($fileSystem);
$some-setFilter($filter);
$some-setSelector($selector);
我想,我們不得不在應用程序的許多地方創建這個對象。如果你不需要依賴的組件後,我們又要去代碼注入部分移除構造函數中的參數或者是setter方法。為了解決這個問題,我們再次返回去使用一個全局註冊表來創建組件。但是,在創建對象之前,它增加了一個新的抽象層:
class SomeComponent
{
// …
/**
* Define a factory method to create SomeComponent instances injecting its dependencies
*/
public static function factory()
{
$connection = new Connection();
$session = new Session();
$fileSystem = new FileSystem();
$filter = new Filter();
$selector = new Selector();
return new self($connection, $session, $fileSystem, $filter, $selector);
}
}
這一刻,我們好像回到了問題的開始,我們正在創建組件內部的依賴,我們每次都在修改以及找尋一種解決問題的辦法,但這都不是很好的做法。
一種實用和優雅的來解決這些問題,是使用容器的依賴注入,像我們在前面看到的,容器作為全局註冊表,使用容器的依賴注入做為一種橋樑來解決依賴可以使我們的代碼耦合度更低,很好的降低了組件的複雜性:
class SomeComponent
{
protected $_di;
public function __construct($di)
{
$this-_di = $di;
}
public function someDbTask()
{
// Get the connection service
// Always returns a new connection
$connection = $this-_di-get(‘db’);
}
public function someOtherDbTask()
{
// Get a shared connection service,
// this will return the same connection everytime
$connection = $this-_di-getShared(‘db’);
//This method also requires a input filtering service
$filter = $this-_db-get(‘filter’);
}
}
$di = new Phalcon\DI();
//Register a “db” service in the container
$di-set(‘db’, function(){
return new Connection(array(
“host” = “localhost”,
“username” = “root”,
“password” = “secret”,
“dbname” = “invo”
));
});
//Register a “filter” service in the container
$di-set(‘filter’, function(){
return new Filter();
});
//Register a “session” service in the container
$di-set(‘session’, function(){
return new Session();
});
//Pass the service container as unique parameter
$some = new SomeComponent($di);
$some-someTask();
現在,該組件只有訪問某種service的時候才需要它,如果它不需要,它甚至不初始化,以節約資源。該組件是高度解耦。他們的行為,或者說他們的任何其他方面都不會影響到組件本身。我們的實現辦法
Phalcon\DI 是一個實現了服務的依賴注入功能的組件,它本身也是一個容器。
由於Phalcon高度解耦,Phalcon\DI 是框架用來集成其他組件的必不可少的部分,開發人員也可以使用這個組件依賴注入和管理應用程序中不同類文件的實例。
基本上,這個組件實現了 Inversion of Control 模式。基於此,對象不再以構造函數接收參數或者使用setter的方式來實現注入,而是直接請求服務的依賴注入。這就大大降低了整體程序的複雜性,因為只有一個方法用以獲得所需要的一個組件的依賴關係。
此外,這種模式增強了代碼的可測試性,從而使它不容易出錯。
在容器中註冊服務
框架本身或開發人員都可以註冊服務。當一個組件A要求調用組件B(或它的類的一個實例),可以從容器中請求調用組件B,而不是創建組件B的一個實例。
這種工作方式為我們提供了許多優點:
我們可以更換一個組件,從他們本身或者第三方輕鬆創建。
在組件發布之前,我們可以充分的控制對象的初始化,並對對象進行各種設置。
我們可以使用統一的方式從組件得到一個結構化的全局實例
服務可以通過以下幾種方式注入到容器:
//Create the Dependency Injector Container
$di = new Phalcon\DI();
//By its class name
$di-set(“request”, ‘Phalcon\Http\Request’);
//Using an anonymous function, the instance will lazy loaded
$di-set(“request”, function(){
return new Phalcon\Http\Request();
});
//Registering directly an instance
$di-set(“request”, new Phalcon\Http\Request());
//Using an array definition
$di-set(“request”, array(
“className” = ‘Phalcon\Http\Request’
));
在上面的例子中,當向框架請求訪問一個請求數據時,它將首先確定容器中是否存在這個」reqeust」名稱的服務。
容器會反回一個請求數據的實例,開發人員最終得到他們想要的組件。
在上面示例中的每一種方法都有優缺點,具體使用哪一種,由開發過程中的特定場景來決定的。
用一個字元串來設定一個服務非常簡單,但缺少靈活性。設置服務時,使用數組則提供了更多的靈活性,而且可以使用較複雜的代碼。lambda函數是兩者之間一個很好的平衡,但也可能導致更多的維護管理成本。
Phalcon\DI 提供服務的延遲載入。除非開發人員在注入服務的時候直接實例化一個對象,然後存存儲到容器中。在容器中,通過數組,字元串等方式存儲的服務都將被延遲載入,即只有在請求對象的時候才被初始化。
//Register a service “db” with a class name and its parameters
$di-set(“db”, array(
“className” = “Phalcon\Db\Adapter\Pdo\Mysql”,
“parameters” = array(
“parameter” = array(
“host” = “localhost”,
“username” = “root”,
“password” = “secret”,
“dbname” = “blog”
)
)
));
//Using an anonymous function
$di-set(“db”, function(){
return new Phalcon\Db\Adapter\Pdo\Mysql(array(
“host” = “localhost”,
“username” = “root”,
“password” = “secret”,
“dbname” = “blog”
));
});
以上這兩種服務的註冊方式產生相同的結果。然後,通過數組定義的,在後面需要的時候,你可以修改服務參數:
$di-setParameter(“db”, 0, array(
“host” = “localhost”,
“username” = “root”,
“password” = “secret”
));
從容器中獲得服務的最簡單方式就是使用」get」方法,它將從容器中返回一個新的實例:
$request = $di-get(“request”);
或者通過下面這種魔術方法的形式調用:
$request = $di-getRequest();
Phalcon\DI 同時允許服務重用,為了得到一個已經實例化過的服務,可以使用 getShared() 方法的形式來獲得服務。
具體的 Phalcon\Http\Request 請求示例:
$request = $di-getShared(“request”);
參數還可以在請求的時候通過將一個數組參數傳遞給構造函數的方式:
$component = $di-get(“MyComponent”, array(“some-parameter”, “other”));
原創文章,作者:JICSK,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/324631.html