秒杀系列03 ~ 理解依赖注入/控制反转

接上文:秒杀系列02

这里列举一个例子,一个Db类(数据库操作),一个User类(业务处理),其中User需要调用Db类查询。

准备一个数据库

关闭防火墙,我们是本地虚拟机,可以不设防火墙,避免连接资源时的限制。

加一张users表,并添加一点数据。

重新生成一个docker镜像

因为我们之前的php环境的镜像,是不支持pdo_mysql扩展的,我们加上。

dockerfile如下:

FROM php:8.2-cli

RUN echo "nameserver 8.8.8.8" > /etc/resolv.conf

RUN apt-get update && apt-get install -y \
    libcurl4-openssl-dev \
    libssl-dev \
    libzip-dev \
    libbrotli-dev \
    libpng-dev \
    default-libmysqlclient-dev \
    unzip && \
    docker-php-ext-install zip pdo pdo_mysql

RUN pecl install swoole && \
    docker-php-ext-enable swoole

RUN pecl install redis && \
    docker-php-ext-enable redis

WORKDIR /var/www

构建为镜像

docker build -t php8.2-swoole-pdo:v1.0.0 .

// 运行
docker run -it --name seckill -p 8001:80 -v /www/wwwroot/learnProject/seckill/v1:/var/www/v1 php8.2-swoole-pdo:v1.0.0 bash

早期的封装方式 ~ 正向控制

在v1根目录下,新建一个test.php文件,内容如下:

<?php
class Db {
    private $pdo;
    public function __construct($dsn) {
        try {
            $this->pdo = new PDO($dsn);
            $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        } catch (PDOException $e) {
            echo "mysql连接失败:" . $e->getMessage();
        }
    }

    public function queryForRows($sql) {
        try {
            $stmt = $this->pdo->query($sql);
            return $stmt->fetchAll(PDO::FETCH_ASSOC);
        } catch (PDOException $e) {
            echo "查询失败:" . $e->getMessage();
        }
    }
}

class User {
    private $db;

    public function __construct($dsn)
    {
        $this->db = new Db($dsn); // 主动实例化Db
    }

    public function getAllUsers() : array {
        return $this->db->queryForRows("select * from users");
    }
}

$dsn = "mysql:host=192.168.0.101;dbname=seckill;charset=utf8;user=seckill;password=BBHyiFWiXrpxji5S;";  // 可以用 .env 文件

$user = new User($dsn);
var_dump($user->getAllUsers());

上面代码存在的问题:

  1. Db 和 User 耦合度太高,存在强关联。
  2. User 是老大,Db 是小弟,按理来说,它们应该是平级的,User关注于业务,Db关注于数据操作。
  3. 执行顺序是 User -> Db,而且是在 User 的里面执行的 Db实例化,可以理解为是一种正向控制。

正确的做法:

不用在 User 中主动实例化 Db了,而是采用,向 User 注入 Db 的实例 。

现在的封装方式 ~ 依赖注入/控制反转

test.php

<?php
class Db {
    private $pdo;
    public function __construct($dsn) {
        try {
            $this->pdo = new PDO($dsn);
            $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        } catch (PDOException $e) {
            echo "mysql连接失败:" . $e->getMessage();
        }
    }

    public function queryForRows($sql) {
        try {
            $stmt = $this->pdo->query($sql);
            return $stmt->fetchAll(PDO::FETCH_ASSOC);
        } catch (PDOException $e) {
            echo "查询失败:" . $e->getMessage();
        }
    }
}

class User {
    private $db;

    public function __construct(Db $Db)   // 这里直接注入Db的实例了
    {
        $this->db = $Db;  // 这里不在主动实例化Db了,直接用注入的Db实例
    }

    public function getAllUsers() : array {
        return $this->db->queryForRows("select * from users");
    }
}

// 执行的顺序发生了改变
// User --> Db
// Db -> User  控制顺序发生了反转 -> 控制反转

$dsn = "mysql:host=192.168.0.101;dbname=seckill;charset=utf8;user=seckill;password=BBHyiFWiXrpxji5S;";  // 可以用 .env 文件
$db = new Db($dsn);  // 现在和 User 地位平等了
$user = new User($db);  // 依赖注入
var_dump($user->getAllUsers());

可以看到,经过上面的封装,Db 和 User 解除了强绑定,变成平级了,User 不再主动实例Db了,而是被动等待 Db依赖的注入,而且执行顺序也发生了改变,变为了 Db -> User,也叫控制反转。

依赖注入 Dependency Injection (DI)

控制反转 Inversion of Control (IoC)

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇