异常处理的最佳实践:PDO+控制器和存储库


Best practice for exception handling: PDO + controllers & repositories

我已经搜索了将异常处理与PDO一起使用的最佳实践,但大多数示例仅从简单的单类方法来看。

如果我在 ORM 类型模型中使用控制器和存储库,各种尝试/捕获和抛出块应该发生在哪里?

一个简化的示例:

控制器:(创建存储库对象,触发 loadProduct 方法,并加载模板)

class ProductController {
    public function viewProduct($product_id) {
        $ProductRepository = new ProductRepository($this->Pdo);
        $Product = $ProductRepository->loadProduct($product_id);
            
        include(__DIR__.'/../templates/product_template.php');
    }
}

模型/存储库:

class ProductRepository
{
    private $Pdo;
        
    public function __construct(PDO $Pdo)
    {
        $this->Pdo = $Pdo;
    }
            
    public function loadProduct($product_id,$withimages=0)
    {
        $Stm = $this->Pdo->prepare('
            SELECT p.product_id,p.model,p.price,p.prodinfo,pi.image_path
            FROM products p LEFT JOIN product_images pi
            ON p.product_id = pi.product_id
            WHERE p.product_id = :product_id
            AND pi.is_primary = 1
        ');
        $Stm->bindParam(':product_id',$product_id,PDO::PARAM_INT);
        $Stm->execute();
    
        return $this->arrayToObject($Stm->fetch(PDO::FETCH_ASSOC));    
    }
}

是否应该将 try/catch 块放入控制器中,并在execute()不返回任何内容时抛出异常? 如果$Pdo->prepare()方法未触发,则引发单独的异常?

通常,异常处理策略非常简单。尤其是PDO。因为PDO仅在严重故障的情况下抛出一个,并且继续执行几乎没有意义 - 因此,仅默认停止是可以的。

因此,对于代码的平均部分,无论是模型、存储库还是其他代码,都不需要专门的处理。

只有在具有失败查询方案的某些位置,才必须使用 try-catch。最常用的方案是事务回滚。因此,如果您有事务,您可能希望将其包装在try中,然后回滚catch.

要回答评论中的澄清:

这是两种本质上不同的场景:

  • 如果 SELECT 找不到产品,也没有什么特别的。
  • 虽然如果 INSERT 以某种方式创建了一个无效的 SQL 查询,这确实是一场灾难。

他们需要不同的处理方式。

对于第一种情况,您根本不需要例外,这是常规行为。只需在您的模板中有一个显示"未找到任何内容"的分支

对于第二个,创建自定义异常处理程序,该处理程序记录错误,发送 503,并显示通用 503 错误页面。