0 传统方法,正向控制
<?php class MyDB { private $db; public function __construct($connInfo) { } public function gueryForRows($sql) { return ['uid'=>111]; } } class MyUser { public $mydb; public function __construct($dsn) { //正向实例化 以myUser控制MyDB $this->mydb = new MyDB($dsn); } public function getAllUsers():array { return $this->mydb->gueryForRows('select * from users'); } } $user = new MyUser('mysql:host=localhost'); $list = $user->getAllUsers(); var_dump($list);
缺点:过度耦合。
1 改进版本1.0 依赖注入、控制反转
<?php class MyDB { private $db; public function __construct($connInfo) { } public function gueryForRows($sql) { return ['uid'=>222]; } } class MyUser { public $mydb; //$dsn配置 // 1 正向控制 public function __construct($dsn) public function __construct(MyDB $DB) { //1 正向实例化 以myUser控制MyDB //$this->mydb = new MyDB($dsn); //MyUser不会主动去实例化DB 控制顺序发生了反转 起到了解耦的目的 $this->mydb = $DB; } public function getAllUsers():array { return $this->mydb->gueryForRows('select * from users'); } } // $user = new MyUser('mysql:host=localhost'); $db = new MyDB('mysql:host=localhost'); //依赖注入 控制反转 向MyUser注入MyDB的实例 $user = new MyUser($db); $list = $user->getAllUsers(); var_dump($list);
优点:MyUser不再主动创建MyDB实例,变成被动等待依赖注入。起到了解耦的目的
2 IoC容器2.0
<?php class MyDB { private $db; public function __construct($connInfo) { } public function gueryForRows($sql) { return ['uid'=>333]; } } class MyUser { public $mydb; //$dsn配置 // 1 正向控制 public function __construct($dsn) public function __construct(MyDB $DB) { //1 正向实例化 以myUser控制MyDB //$this->mydb = new MyDB($dsn); //MyUser不会主动去实例化DB 控制顺序发生了反转 起到了解耦的目的 $this->mydb = $DB; } public function getAllUsers():array { return $this->mydb->gueryForRows('select * from users'); } } class ClassFactory { //容器 用来存放实例化后的类 private static $container = []; public static function set(String $name,callable $func){ self::$container[$name] = $func; } public static function getObject(string $name){ if (isset(self::$container[$name])){ //执行匿名函数 return (self::$container[$name])(); } return null; } } // 1 正向控制 // $user = new MyUser('mysql:host=localhost'); // 2 控制反转 /*$db = new MyDB('mysql:host=localhost'); //依赖注入 控制反转 向MyUser注入MyDB的实例 $user = new MyUser($db);*/ // 3 IoC容器 // 3.1 往容器里注入mydb实例 ClassFactory::set('mydb',function (){ return new MyDB('mysql:host=localhost'); }); // 3.2 往容器里注入mydb实例 ClassFactory::set('my_user',function (){ return new MyUser(ClassFactory::getObject('mydb')); }); //3.3获取user实例 $user = ClassFactory::getObject('my_user'); $list = $user->getAllUsers(); var_dump($list);
IoC容器:为了让我们的代码更具维护性,把注入这个过程隐藏起来,放到了一个专门的“容器”里面管理
在swoole出现之后,ClassFactory可以常驻内存。
3 第三方DI库3.0
安装
composer require php-di/php-di
3.1 使用方式一:简单使用(手工方式)不推荐
<?php require_once __DIR__.'/vendor/autoload.php'; class MyDB { private $db; public function __construct($connInfo) { } public function gueryForRows($sql) { return ['uid'=>444]; } } class MyUser { public $mydb; //$dsn配置 // 1 正向控制 public function __construct($dsn) public function __construct(MyDB $DB) { //1 正向实例化 以myUser控制MyDB //$this->mydb = new MyDB($dsn); //MyUser不会主动去实例化DB 控制顺序发生了反转 起到了解耦的目的 $this->mydb = $DB; } public function getAllUsers():array { return $this->mydb->gueryForRows('select * from users'); } } /*class ClassFactory { //容器 用来存放实例化后的类 private static $container = []; public static function set(String $name,callable $func){ self::$container[$name] = $func; } public static function getObject(string $name){ if (isset(self::$container[$name])){ //执行匿名函数 return (self::$container[$name])(); } return null; } }*/ // 1 正向控制 // $user = new MyUser('mysql:host=localhost'); // 2 控制反转 /*$db = new MyDB('mysql:host=localhost'); //依赖注入 控制反转 向MyUser注入MyDB的实例 $user = new MyUser($db);*/ // 3 IoC容器 // 3.1 往容器里注入mydb实例 /*ClassFactory::set('mydb',function (){ return new MyDB('mysql:host=localhost'); }); // 3.2 往容器里注入mydb实例 ClassFactory::set('my_user',function (){ return new MyUser(ClassFactory::getObject('mydb')); }); //3.3获取user实例 $user = ClassFactory::getObject('my_user');*/ //4 使用DI组件 $container = new DIContainer(); $container->set('mydb',function (){ return new MyDB('mysql:host=localhost'); }); $container->set('my_user',function (DIContainer $c){ return new MyUser($c->get('mydb')); }); $user = $container->get('my_user'); $list = $user->getAllUsers(); var_dump($list);
3.2 使用方式二:配置的方法加载类(推荐)
D:seckillproapp estMyDB.php
<?php /** * Created by PhpStorm. * User: SUN * Date: 2021/11/12 * Time: 23:24 */ namespace App est; class MyDB { private $db; public function __construct($connInfo) { } public function gueryForRows($sql) { return ['uid'=>555]; } }
D:seckillproapp estMyUser.php
<?php /** * Created by PhpStorm. * User: SUN * Date: 2021/11/12 * Time: 23:25 */ namespace App est; class MyUser { public $mydb; //$dsn配置 // 1 正向控制 public function __construct($dsn) public function __construct(MyDB $DB) { //1 正向实例化 以myUser控制MyDB //$this->mydb = new MyDB($dsn); //MyUser不会主动去实例化DB 控制顺序发生了反转 起到了解耦的目的 $this->mydb = $DB; } public function getAllUsers():array { return $this->mydb->gueryForRows('select * from users'); } }
D:seckillproapp esteans.php
<?php namespace App est; return [ MyDB::class=>function (){ return new MyDB('mysql:host=localhost'); }, // my_user是我起的名,最好用 MyUser::class更规范化 /* 'my_user'=>function (DIContainer $c){ return new MyUser($c->get(mydb)); },*/ MyUser::class =>function (DIContainer $c){ return new MyUser($c->get(MyDB::class)); } ];
D:seckillpro est.php
<?php require_once __DIR__.'/vendor/autoload.php'; $builder = new DIContainerBuilder(); //扫描所有的配置 $builder->addDefinitions(__DIR__."/app/test/beans.php"); $container = $builder->build(); $user = $container->get(App estMyUser::class); //echo App estMyUser::class.'------';//App estMyUser $list = $user->getAllUsers(); var_dump($list);