PHP容器
PHP容器介绍应用场景例子Laravel框架底层对容器的使用参考资料介绍可以理解为一个盒子,事先将项目中可能用到的类扔进去,在项目中直接从容器中拿,也就是避免了直接在项目中到处new,造成大量耦合。取而代之的是在项目类里面增设setDi、getDi方法,通过Di(依赖注入)统一管理类。应用场景需要灵活管理一大堆具有依赖关系的对象时,比如一个PHP框架需要管理众多服务时。例子1.定义了一...
·
介绍
可以理解为一个盒子,事先将项目中可能用到的类扔进去,在项目中直接从容器中拿,也就是避免了直接在项目中到处new,造成大量耦合。取而代之的是在项目类里面增设setDi、getDi方法,通过Di(依赖注入)统一管理类。
应用场景
需要灵活管理一大堆具有依赖关系的对象时,比如一个PHP框架需要管理众多服务时。
例子
1.定义了一个存储接口,以及两个类实现
<?php
interface Storage{
public function open();
}
class DatabaseStorage implements Storage {
public function open() {
echo 'open db Storage';
}
}
class FileStorage implements Storage {
public function open() {
echo 'open file Storage';
}
}
2.创建一个容器
// 容器
class Container {
protected $binds; // 绑定闭包
protected $instances; // 绑定实例
/**
* 向容器中注册服务
*
* @param $abstract 服务名称
* @param $conctete 服务体
*/
public function bind($abstract, $concrete) {
// 如果是个闭包则绑定到binds中
if ($concrete instanceof Closure) {
$this->binds[$abstract] = $concrete;
} else {
// 否则绑定到实例数组中
$this->instances[$abstract] = $concrete;
}
}
/**
* 从容器中获取服务
*
* @param $abstract 服务名称
* @param $params 实例化服务所需要传递的参数
*/
public function make($abstract, $params = []) {
// 如果是个实例就返回这个实例
if (isset($this->instances[$abstract])) {
return $this->instances[$abstract];
}
array_unshift($params, $this);
// 返回闭包执行结果
return call_user_func_array($this->binds[$abstract], $params);
}
}
3.使用容器,注册服务到容器中,并拿出来使用
$Container = new Container;
// 把名称为FileStorage,内容为闭包的服务,注册到容器
$Container->bind('FileStorage', function($Container) {
return new FileStorage;
});
// 把名称为DatabaseStorage,内容为DatabaseStorage实例的服务注册到容器
$Container->bind('DatabaseStorage', new DatabaseStorage);
// 从容器获取服务并使用
$FileStorage = $Container->make('FileStorage');
$FileStorage->open(); // open file Storage
$DatabaseStorage = $Container->make('DatabaseStorage');
$DatabaseStorage->open(); // open db Storage
Laravel框架底层对容器的使用
1.看bootstrap/app.php
部分代码。
<?php
// 该Application类继承了Container容器类,这里实例化了Application这个容器
// 传递的path参数,是为了把程序的绝对路径绑定到容器
$app = new Illuminate\Foundation\Application(
realpath(__DIR__.'/../')
);
...
2.看new Illuminate\Foundation\Application
发生的事情。
<?php
...
public function __construct($basePath = null)
{
$this->registerBaseBindings();
$this->registerBaseServiceProviders();
$this->registerCoreContainerAliases();
if ($basePath) {
// 设置基本目录这个方法中又调用了bindPathsInContainer方法
$this->setBasePath($basePath);
}
}
...
// 把基础的path的绑定,放到容器中
protected function bindPathsInContainer()
{
$this->instance('path', $this->path());
$this->instance('path.base', $this->basePath());
$this->instance('path.lang', $this->langPath());
$this->instance('path.config', $this->configPath());
$this->instance('path.public', $this->publicPath());
$this->instance('path.storage', $this->storagePath());
$this->instance('path.database', $this->databasePath());
$this->instance('path.resources', $this->resourcePath());
$this->instance('path.bootstrap', $this->bootstrapPath());
}
...
3.由上可见,已经把一些path绑定到了容器中,那么比如我们用public_path()时,底层是如何返回给我们的呢?
当然了,就是从这个容器中再取出来!
// vendor/laravel/framework/src/Illuminate/Foundation/helpers.php
...
if (! function_exists('public_path')) {
/**
* Get the path to the public folder.
*
* @param string $path
* @return string
*/
function public_path($path = '')
{
return app()->make('path.public').($path ? DIRECTORY_SEPARATOR.$path : $path);
}
}
...
参考资料
https://blog.csdn.net/qq_39647045/article/details/83659028
https://segmentfault.com/a/1190000015449325
https://www.jianshu.com/p/e0583692521c
更多推荐
已为社区贡献6条内容
所有评论(0)