很多站长朋友们都不太清楚php依赖注入例子,今天小编就来给大家整理php依赖注入例子,希望对各位有所帮助,具体内容如下:
本文目录一览: 1、 实现地址自动识别实例(PHP) 2、 php依赖注入是在构造函数中注入吗 3、 thinkphp中容器是什么?依赖注入是什么? 4、 PHP中什么是依赖注入 5、 php怎么实例化有依赖注入的类 6、 自定义类的依赖注入 实现地址自动识别实例(PHP)文章正文
址自动识别现在普遍,特别是用在快递填写地址,姓名,手机号码的时候,会把这些按照一定的规范填写后,点击自动识别后,会自动填写到各自的input。最近也简单的实现了这个功能,给后台添加用户的时候,自动识别地址。以下是效果图
具体问题具体分析!代码实现基于laravel完成。一个laravel完整的功能得具备这些:路由route,Model, View, Controller, 我这里用的有依赖注入服务容器等功能,当然,用到地址,你首先要有地址库。。。
下面来看看是如何实现的,这里我只贴出核心代码
UsersController控制器
在这里新建构造函数,实现容器的依赖注入 UsersRepository
接下来就新建地址识别的方法, $discernDel 接收的数据是从前端传过来的,后面再贴前端代码。 业务代码处理交给容器 UsersRepository 里的方法 getDiscern 处理
来看看 userRepository容器处理地址识别的各种业务代码
上面的方法处理手机,名称,和地址处理,地址处理有些繁杂,因为有时候填写的地址有不一样的,比如广西省,有些就填写广西壮族自治区,所以 getAddressArrar 方法处理地址匹配信息,根据自己的业务做调整,如下
前端html部分代码
基本上能看得懂的。jquery用到 getDiscern(); 方法,手机号码,姓名,地址等input这里就不一一列出了。大家根据下面的jquery都能想象到
jquery代码部分
ajax post后交给url: getDiscern 处理,这个就是上面controller的方法,success返回的数据后再追加到每个input里,最后再清除掉自动识别地址框的数据
整个过程简单,又清晰明了,以上就是我的代码,分享给大家,觉得哪个地方不对劲的,欢迎留言吐槽!
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.
依赖注入真的是更易维护,更易测试和更加模块化的答案。
thinkphp中容器是什么?依赖注入是什么?依赖注入:即允许通过类的方法传递对象的能力,并且限制了对象的类型(约束);
而传递的对象背后的那个类被自动绑定并且实例化了,这就是依赖注入;
支持使用依赖注入的场景包括(但不限于):
控制器架构方法; 控制器操作方法; 路由的闭包定义; 事件类的执行方法; 中间件的执行方法;
依赖注入的类统一由容器管理的,大多数情况下是自动绑定和自动实例化的;
PHP中什么是依赖注入依赖注入可能是我所知道的最简单设计模式之一,很多情况下可能你无意识中已经使用了依赖注入。不过它也是最难解释的一个。我认为有一部分原因是由于大多数介绍依赖注入的例子缺乏实际意义,让人难理解。因为PHP主要用于Web开发,那就先来看一个简单的web开发实例。
HTTP本身是一个无状态的连接协议,为了支持客户在发起WEB请求时应用程序能存储用户信息,我们就需要通过一种技术来实现存储状态交互。理所当然最简单的是使用cookie,更好的方式是PHP内置的Session机制。
$_SESSION['language'] = 'fr';
上面代码将用户语言存储在了名为language的Session变量中,因此在该用户随后的请求中,可以通过全局数组$_SESSION来获取language:
$user_language = $_SESSION['language'];
依赖注入主要用于面向对像开发,现在让我们假设我们有一个SessionStorage类,该类封装了PHP Session机制:
class SessionStorage
{
function __construct($cookieName = 'PHP_SESS_ID')
{
session_name($cookieName);
session_start();
}
function set($key, $value)
{
$_SESSION[$key] = $value;
}
function get($key)
{
return $_SESSION[$key];
}
// ...
}
同时还有一个User类提供了更高级的封装:
class User
{
protected $storage;
function __construct()
{
$this->storage = new SessionStorage();
}
function setLanguage($language)
{
$this->storage->set('language', $language);
}
function getLanguage()
{
return $this->storage->get('language');
}
// ...
}
代码很简单,同样使用User类也很简单:
$user = new User();
$user->setLanguage('fr');
$user_language = $user->getLanguage();
一切都很美好,除非你的程序需要更好的扩展性。假设现在你想要更改保存session_id的COOKIE键值,以下有一些可供选择的方法:
User类中创建SessionStorage实例时,在SessionStorage构造方法中使用字符串’SESSION_ID’硬编码:
class User
{
function __construct()
{
$this->storage = new SessionStorage('SESSION_ID');
}
// ...
}
在User类外部设置一个常量(名为STORAGE_SESSION_NAME)
class User
{
function __construct()
{
$this->storage = new SessionStorage(STORAGE_SESSION_NAME);
}
// ...
}
define('STORAGE_SESSION_NAME', 'SESSION_ID');
通过User类构造函数中的参数传递Session name
class User
{
function __construct($sessionName)
{
$this->storage = new SessionStorage($sessionName);
}
// ...
}
$user = new User('SESSION_ID');
还是通过User类构造函数中的参数传递Session name,不过这次参数采用数组的方式
class User
{
function __construct($storageOptions)
{
$this->storage = new SessionStorage($storageOptions['session_name']);
}
// ...
}
$user = new User(array('session_name' => 'SESSION_ID'));
上面的方式都很糟糕。
在user类中硬编码设置session name的做法没有真正解决问题,如果以后你还需要更改保存session_id的COOKIE键值,你不得不再一次修改user类(User类不应该关心COOKIE键值)。
使用常量的方式同样很糟,造成User类依赖于一个常量设置。
通过User类构造函数的参数或数组来传递session name相对来说好一些,不过也不完美,这样做干扰了User类构造函数的参数,因为如何存储Session并不是User类需要关心的,User类不应该和它们扯上关联。
另外,还有一个问题不太好解决:我们如何改变SessionStorage类。这种应用场景很多,比如你要用一个Session模拟类来做测试,或者你要将Session存储在数据库或者内存中。目前这种实现方式,在不改变User类的情况下,很难做到这点。
现在,让我们来使用依赖注入。回忆一下,之前我们是在User类内部创建SessionStorage对像的,现在我们修改一下,让SessionStorage对像通过User类的构造函数传递进去。
class User
{
function __construct($storage)
{
$this->storage = $storage;
}
// ...
这就是依赖注入最经典的案例,没有之一。现在使用User类有一些小小的改变,首先你需要创建SessionStorage对像。
$storage = new SessionStorage('SESSION_ID');
$user = new User($storage);
现在,配置session存储对像很简单了,同样如果改变session存储对像也很简单,所有这一切并不需要去更新User类,降低了业务类之间的耦合。
Pico Container 的网站上是这样描述依赖注入:
依赖注入是通过类的构造函数、方法、或者直接写入的方式,将所依赖的组件传递给类的方式。
所以依赖注入并不只限于通过构造函数注入。下面来看看几种注入方式:
构造函数注入
class User
{
function __construct($storage)
{
$this->storage = $storage;
}
// ...
}
setter方法注入
class User
{
function setSessionStorage($storage)
{
$this->storage = $storage;
}
// ...
}
属性直接注入
class User
{
public $sessionStorage;
}
$user->sessionStorage = $storage;
根据经验,一般通过构造函数注入的是强依赖关系的组件,setter方式用来注入可选的依赖组件。
现在,大多数流行的PHP框架都采用了依赖注入的模式实现业务组件间的高内聚低耦合。
// symfony: 构造函数注入的例子
$dispatcher = new sfEventDispatcher();
$storage = new sfMySQLSessionStorage(array('database' => 'session', 'db_table' => 'session'));
$user = new sfUser($dispatcher, $storage, array('default_culture' => 'en'));
// Zend Framework: setter方式注入的例子
$transport = new Zend_Mail_Transport_Smtp('smtp.gmail.com', array(
'auth' => 'login',
'username' => 'foo',
'password' => 'bar',
'ssl' => 'ssl',
'port' => 465,
));
$mailer = new Zend_Mail();
$mailer->setDefaultTransport($transport);
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"));
自定义类的依赖注入一、自定义类
新建文件:App\demo\fx.php
二、将fx类绑定到容器:
首先用artisan命令创建服务者:php artisan make:provider myServiceProvider
然后绑定自定义类fx
三、将服务者myServiceProvider注册到config\app.php中:
四、控制器中实现依赖注入
关于php依赖注入例子的介绍到此就结束了,不知道本篇文章是否对您有帮助呢?如果你还想了解更多此类信息,记得收藏关注本站,我们会不定期更新哦。
查看更多关于php依赖注入例子 php依赖注入在框架中的使用的详细内容...