内容简介:Laravel 是当今最流行、最常使用的开源现代 web 应用框架之一。它提供了一些独特的特性,比如 Eloquent ORM, Query 构造器,Homestead 等时髦的特性,这些特性只有 Laravel 中才有。我喜欢 Laravel 是由于它犹如建筑风格一样的独特设计。Laravel 的底层使用了多设计模式,比如单例、工厂、建造者、门面、策略、提供者、代理等模式。随着本人知识的增长,我越来越发现 Laravel 的美。Laravel 为开发者减少了苦恼,带来了更多的便利。
Laravel 是当今最流行、最常使用的开源现代 web 应用框架之一。它提供了一些独特的特性,比如 Eloquent ORM, Query 构造器,Homestead 等时髦的特性,这些特性只有 Laravel 中才有。
我喜欢 Laravel 是由于它犹如建筑风格一样的独特设计。Laravel 的底层使用了多设计模式,比如单例、工厂、建造者、门面、策略、提供者、代理等模式。随着本人知识的增长,我越来越发现 Laravel 的美。Laravel 为开发者减少了苦恼,带来了更多的便利。
学习 Laravel,不仅仅是学习如何使用不同的类,还要学习 Laravel 的哲学,学习它优雅的语法。Laravel 哲学的一个重要组成部分就是 IoC 容器,也可以称为服务容器。它是一个 Laravel 应用的核心部分,因此理解并使用 IoC 容器是我们必须掌握的一项重要技能。
IoC 容器是一个非常强大的类管理工具。它可以自动解析类。接下来我会试着去说清楚它为什么如此重要,以及它的工作原理。
首先,我想先谈下依赖反转原则,对它的了解会有助于我们更好地理解 IoC 容器的重要性。
该原则规定:
抽象接口不应该依赖于具体实现。而具体实现则应该依赖于抽象接口。
一言以蔽之: 依赖于抽象而非具体
class MySQLConnection
{
/**
* 数据库连接
*/
public function connect()
{
var_dump(‘MYSQL Connection’);
}
}
class PasswordReminder
{
/**
* @var MySQLConnection
*/
private $dbConnection;
public function __construct(MySQLConnection $dbConnection)
{
$this->dbConnection = $dbConnection;
}
}
大家常常会有一个误解,那就是依赖反转就只是依赖注入的另一种说法。但其实二者是不同的。在上面的代码示例中,尽管在 PasswordReminder 类中注入了 MySQLConnection 类,但它还是依赖于 MySQLConnection 类。
然而,高层次模块 PasswordReminder 是不应该依赖于低层次模块 MySQLConnection 的。
如果我们想要把 MySQLConnection 改成 MongoDBConnection,那我们就还得手动修改 PasswordReminder 类构造函数里的依赖。
PasswordReminder 类应该依赖于抽象接口,而非具体类。那我们要怎么做呢?请看下面的例子:
interface ConnectionInterface
{
public function connect();
}
class DbConnection implements ConnectionInterface
{
/**
* 数据库连接
*/
public function connect()
{
var_dump(‘MYSQL Connection’);
}
}
class PasswordReminder
{
/**
* @var DBConnection
*/
private $dbConnection;
public function __construct(ConnectionInterface $dbConnection)
{
$this->dbConnection = $dbConnection;
}
}
通过上面的代码,如果我们想把 MySQLConnection 改成 MongoDBConnection,根本不需要去修改 PasswordReminder 类构造函数里的依赖。因为现在 PasswordReminder 类依赖的是接口,而非具体类。
如果你对接口的概念还不是很了解,可以看下 这篇文章 。它会帮助你理解依赖反转原则和 IoC 容器等。
现在我要讲下 IoC 容器里到底发生了什么。我们可以把 IoC 容器简单地理解为就是一个容器,里面装的是类的依赖。
OrderRepositoryInterface 接口:
namespace App\Repositories;
interface OrderRepositoryInterface
{
public function getAll();
}
DbOrderRepository 类:
namespace App\Repositories;
class DbOrderRepository implements OrderRepositoryInterface
{
function getAll()
{
return 'Getting all from mysql';
}
}
OrdersController 类:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Repositories\OrderRepositoryInterface;
class OrdersController extends Controller
{
protected $order;
function __construct(OrderRepositoryInterface $order)
{
$this->order = $order;
}
public function index()
{
dd($this->order->getAll());
return View::make(orders.index);
}
}
路由:
Route::resource('orders', 'OrdersController');
现在,在浏览器中输入这个地址 <http://localhost:8000/orders>
报错了吧,错误的原因是服务容器正在尝试去实例化一个接口,而接口是不能被实例化的。解决这个问题,只需把接口绑定到一个具体的类上:
把下面这行代码加在路由文件里就搞定了:
App::bind('App\Repositories\OrderRepositoryInterface', 'App\Repositories\DbOrderRepository');
现在刷新浏览器看看:
我们可以这样定义一个容器类:
class SimpleContainer
{
protected static $container = [];
public static function bind($name, Callable $resolver)
{
static::$container[$name] = $resolver;
}
public static function make($name)
{
if(isset(static::$container[$name])){
$resolver = static::$container[$name] ;
return $resolver();
}
throw new Exception("Binding does not exist in containeer");
}
}
这里,我想告诉你服务容器解析依赖是多么简单的事。
class LogToDatabase
{
public function execute($message)
{
var_dump('log the message to a database :'.$message);
}
}
class UsersController {
protected $logger;
public function __construct(LogToDatabase $logger)
{
$this->logger = $logger;
}
public function show()
{
$user = 'JohnDoe';
$this->logger->execute($user);
}
}
绑定依赖:
SimpleContainer::bind('Foo', function()
{
return new UsersController(new LogToDatabase);
});
$foo = SimpleContainer::make('Foo');
print_r($foo->show());
输出:
string(36) "Log the messages to a file : JohnDoe"
Laravel 的服务容器源码:
public function bind($abstract, $concrete = null, $shared = false)
{
$abstract = $this->normalize($abstract);
$concrete = $this->normalize($concrete);
if (is_array($abstract)) {
list($abstract, $alias) = $this->extractAlias($abstract);
$this->alias($abstract, $alias);
}
$this->dropStaleInstances($abstract);
if (is_null($concrete)) {
$concrete = $abstract;
}
if (! $concrete instanceof Closure) {
$concrete = $this->getClosure($abstract, $concrete);
}
$this->bindings[$abstract] = compact('concrete', 'shared');
if ($this->resolved($abstract)) {
$this->rebound($abstract);
}
}
public function make($abstract, array $parameters = [])
{
$abstract = $this->getAlias($this->normalize($abstract));
if (isset($this->instances[$abstract])) {
return $this->instances[$abstract];
}
$concrete = $this->getConcrete($abstract);
if ($this->isBuildable($concrete, $abstract)) {
$object = $this->build($concrete, $parameters);
} else {
$object = $this->make($concrete, $parameters);
}
foreach ($this->getExtenders($abstract) as $extender) {
$object = $extender($object, $this);
}
if ($this->isShared($abstract)) {
$this->instances[$abstract] = $object;
}
$this->fireResolvingCallbacks($abstract, $object);
$this->resolved[$abstract] = true;
return $object;
}
public function build($concrete, array $parameters = [])
{
if ($concrete instanceof Closure) {
return $concrete($this, $parameters);
}
$reflector = new ReflectionClass($concrete);
if (! $reflector->isInstantiable()) {
if (! empty($this->buildStack)) {
$previous = implode(', ', $this->buildStack);
$message = "Target [$concrete] is not instantiable while building [$previous].";
} else {
$message = "Target [$concrete] is not instantiable.";
}
throw new BindingResolutionException($message);
}
$this->buildStack[] = $concrete;
$constructor = $reflector->getConstructor();
if (is_null($constructor)) {
array_pop($this->buildStack);
return new $concrete;
}
$dependencies = $constructor->getParameters();
$parameters = $this->keyParametersByArgument(
$dependencies, $parameters
);
$instances = $this->getDependencies($dependencies,$parameters);
array_pop($this->buildStack);
return $reflector->newInstanceArgs($instances);
}
如果你想了解关于服务容器的更多内容,可以看下 vendor/laravel/framwork/src/Illuminate/Container/Container.php
简单的绑定
$this->app->bind('HelpSpot\API', function ($app) {
return new HelpSpot\API($app->make('HttpClient'));
});
单例模式绑定
通过 singleton 方法绑定到服务容器的类或接口,只会被解析一次。
$this->app->singleton('HelpSpot\API', function ($app) {
return new HelpSpot\API($app->make('HttpClient'));
});
绑定实例
也可以通过 instance 方法把具体的实例绑定到服务容器中。之后,就会一直返回这个绑定的实例:
$api = new HelpSpot\API(new HttpClient);
$this->app->instance('HelpSpot\API', $api);
如果没有绑定,PHP 会利用反射机制来解析实例和依赖。
如果想了解更多细节,可以查看 官方文档
关于 Laravel 服务容器的练习代码, 可以从我的 GitHub (如果喜欢,烦请不吝 star )仓库获取。
感谢阅读。
以上所述就是小编给大家介绍的《为什么我们需要 Laravel IoC 容器?》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 关于容器,你真的需要听听老王怎么说
- 我的数据中心需要什么样的容器化技术?
- 容器编排无法解决微服务的所有问题,你还需要服务网格
- 现代云原生架构:关于微服务、容器和无服务器你需要了解的
- Mars-java 2.2.2 发布,不需要容器的 Java Web 开发框架
- 云计算也需要维护 SDN也需要网工 只不过更智能了
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Approximation Algorithms
Vijay V. Vazirani / Springer / 2001-07-02 / USD 54.95
'This book covers the dominant theoretical approaches to the approximate solution of hard combinatorial optimization and enumeration problems. It contains elegant combinatorial theory, useful and inte......一起来看看 《Approximation Algorithms》 这本书的介绍吧!