0

对于加载类,我使用 PSR-4 自动加载。在我的index.php我使用 FastRoute 组件。在那里index.php我创建了 $db 连接并将其传递给控制器​​。

call_user_func_array([new $class($db), $method], $vars);

在控制器中,我收到它并将其传递给模型并在那里使用它。我知道这是不好的方法。在index.php我如何在我的模型中使用它而不通过控制器等并且没有连接的单例实例时创建的数据库连接?如何使用 DI 或 DIC 设置数据库连接index.php并进入所有模型?

索引.php:

<?php

require_once 'vendor/autoload.php';

$db = new DbConnection(new DbConfig($config));

$dispatcher = FastRoute\simpleDispatcher(function(FastRoute\RouteCollector $r) {
    $r->addRoute('GET', '/users', 'UserController/actionGetAllUsers');
    $r->addRoute('GET', '/users/{id:\d+}', 'UserController/actionGetUserById');
});

// Fetch method and URI from somewhere
$httpMethod = $_SERVER['REQUEST_METHOD'];
$uri = $_SERVER['REQUEST_URI'];

// Strip query string (?foo=bar) and decode URI
if (false !== $pos = strpos($uri, '?')) {
    $uri = substr($uri, 0, $pos);
}
$uri = rawurldecode($uri);

switch ($routeInfo[0]) {
    case FastRoute\Dispatcher::NOT_FOUND:
        // ... 404 Not Found
        break;
    case FastRoute\Dispatcher::METHOD_NOT_ALLOWED:
        $allowedMethods = $routeInfo[1];
        // ... 405 Method Not Allowed
        break;
    case FastRoute\Dispatcher::FOUND:
        $handler = $routeInfo[1];
        $vars = $routeInfo[2];
        list($class, $method) = explode("/", $handler, 2);
        $module = strtolower(str_replace('Controller', '', $class));
        $class = 'Vendorname\\' . $module . '\\controllers\\' . $class;
        $routeInfo = $dispatcher->dispatch($httpMethod, $uri);
        call_user_func_array([new $class($db), $method], $vars);
        break;
} 

控制器:

class UserController extends BaseApiController
{
    protected $db;

    public function __construct($db)
    {
        $this->db = $db;
        parent::__construct();
    }

    public function actionGetAllUsers()
    {
        $model = new User($this->db);
        echo json_encode($model->getAllUsers());
    }

模型:

class User
{
    protected $db;

    public function __construct($db)
    {
        $this->db = $db;
    }

    public function getAllUsers()
    {
        $stmt = $this->db->prepare('SELECT * FROM user');
        $stmt->execute();
        return $stmt->fetchAll(\PDO::FETCH_ASSOC);
    }
4

1 回答 1

1

首先你要明白,“依赖注入”和“依赖注入容器”是两个不同的东西:

  • DI 是一种技术,用于在 OOP 中分离两个类。
  • DIC 是一个软件,它组装对象图

看来,您已经是,您传递数据库连接的方式很糟糕。确切的技术原因可以描述为违反LoD。基本上,您的$db变量跨越了两层边界。

但是,解决方案不是:“只需添加 DI 容器”。那不会解决问题。相反,您应该改进模型层的设计。你可以在这里快速阅读,但我会在这里给出一个更短的版本:

  • 将持久性逻辑与域逻辑分开
  • 控制器应该依赖于服务,这将是控制器(存在于 UI 层中)与业务逻辑交互的方式。
  • 分离业务逻辑的最简单方法分为三个部分:数据映射器(处理持久性逻辑)、域对象(用于业务规则)和服务(域对象和持久性对象之间的交互)

数据库应该是数据映射器的依赖项,专门用于处理用户实例(更多here)。该映射器应该是您的“帐户管理服务”的直接依赖项(想一个好名字),或者使用该服务内部的工厂构建(然后这个工厂将成为服务的依赖项。

PS至于“选择哪个 DIC”,我个人是用Symfony 的独立容器,但这纯粹是个人喜好。

于 2017-07-20T13:42:37.877 回答