之前看了好多框架,laravel,thinkphp,yii等等。基本上都使用了容器。对于我而言,虽然看懂了laravel是怎么写的,但是如果自己不去尝试一下,始终觉得不会这个东西。
下面的代码是我实现的一个简单的容器,很多地方处理并不是很好,但是应该已经足够了。
<?php
class Container{
//$binds 这个变量保存,是名字=>实例的映射
private $binds = [];
public static $instance = null;
/**
* 单例
*/
public static function getInstance(){
if(static::$instance == null){
static::$instance = new static();
return static::$instance ;
}
return static::$instance;
}
/**
* 一开始是受到laravel的影响,所以写了一个bind函数,
* 看完laravel的容器实现,印象之中,$concrete和$abstract来回变换。
* 下面的代码有点像thinkphp的里面的实现,好理解一点
*/
public static function bind($name,$class = null){
if($class instanceof Closure){
static::getInstance()->binds[$name] = $class;
}else if(is_object($class)){
static::getInstance()->binds[$name] = $class;
}else{
//在这里开始make一个数组,laravel好像是make和build分开的。
static::getInstance()->make($name);
}
}
/**
* 核心是make方法了
*/
public static function get($name){
return static::getInstance()->make($name);
}
/**
* 核心make方法
*/
public function make($name){
try{
//根据类名去查找$this->binds实例是否已经存在,如果存在就直接返回
if(array_key_exists($name,$this->binds)){
return $this->binds[$name];
}
//根据类名得到它的反射类
$reflectClass = new ReflectionClass($name);
//利用反射类
$constructor = $reflectClass->getConstructor();
//如果没有构造器的话,就直接去实例化它
$params = [];
if(!is_null($constructor)){
//获取构造器中的方法
$constructorParams = $constructor->getParameters();
// var_dump($constructorParams);
//保存构造器的参数
foreach($constructorParams as $constructorParam){
//这个地方主要是判断参数是否是类,如果是就递归的构造它,不是就简单的添加到$this->params中
if(!is_null($constructorParam->getType())){
$params[] =$this->make($constructorParam->name,$constructorParam->name);
}else{
$params[] = $constructorParam->name;
}
}
}
//在这个地方构造实例
$class = $reflectClass->newInstanceArgs($params);
//绑定
$this->binds[$name] = $class;
return $class;
}catch(ReflectionException $e){
echo $e->getMessage();
}
}
private function __construct(){}
private function __clone(){}
}
?>
下面是我的测试文件了,
<?php
require "./Container.php";
class TestFather{
private $name = "TestFather";
public function __construct(){
}
}
class Test extends TestFather{
private $name = "Test";
// public function __construct(DI $di, DI2 $di2,$name){
// }
public function __construct(DI $di,$name,$param_2 =[]){
}
public function sayName(){
echo $this->name;
}
public function sayDI2Name(DI2 $di2){
//如果这么写的,di2方法会先于前面的字符串打印出来
// echo "form Test say di2 name: ".$di2->sayName();
echo "form Test say di2 name: ";
echo $di2->sayName();
}
}
class DI{
private $name = "DI";
public function __construct(DI2 $di2){}
public function sayName(){
echo $this->name;
}
}
class DI2{
private $name = "DI2";
public function __construct(){}
public function sayName(){
echo $this->name;
}
}
class DI3{
private $name = "DI3";
public function __construct(){}
public function sayName(){
echo $this->name;
}
}
class DI4{
private $name = "DI4";
public function __construct(){}
public function sayName(){
echo $this->name;
}
}
//要不要无所谓了
// Container::bind('test','Test');
$test = Container::get('test');
$test->sayName();
echo "\n";
$test->sayDI2Name(new DI2());
echo "\n";
$di = Container::get('di');
$di->sayName();
echo "\n";
$di2 = Container::get('di2');
$di2->sayName();
echo "\n";
$di3 = new DI3();
Container::get('di3',$di3)->sayName();
echo "\n";
$di4 = function(){
return new DI4();
};
Container::get('di4',$di4)->sayName();
echo "\n";
?>
最后的结果如下
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。