即使语句在try / catch块中,也未捕获到异常PDOException

时间:2019-02-13 02:28:03

标签: php

在测试使用我的数据库实用程序类的应用程序时,我遇到了意外的致命错误(请参见下面的代码)。这是执行的测试的简要记录:

  1. 新产品已添加到数据库
  2. 新产品已下订单
  3. 试图删除新产品(仍在订单上使用它)

结果:

  • 按预期,数据库中的外键约束阻止了产品的删除
  • 出乎意料的是,显示了以下致命错误-
    Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[23000]: [Microsoft][SQL Server Native Client 11.0][SQL Server]The DELETE statement conflicted with the REFERENCE constraint "FK_Orders_Products". The conflict occurred in database "AppTEST", table "dbo.Orders", column 'productID'.' in C:\xampp\htdocs\App\classes\utility\DB.php:140 Stack trace: ...

    第140行是$stmt->execute();,位于query()方法的下面的代码。

    论坛中描述类似错误的帖子称我在全局类前面加了一个反斜杠,但我没有这样做。为什么会发生致命错误?

这是我的数据库实用程序类中有关此问题的相关部分:

namespace classes\utility;

use \PDO,
    \Exception,
    \PDOException;

class DB
{
    private $_pdo,          # stores PDO object when it's instantiated
            $_error,        # stores whether query failed or not
            $_results,      # stores dataset returned by query
            $_count = 0;    # stores number of data rows returned

    /*connect to database*/
    private function __construct()
    {
        try
        {
            $connection = new \PDO('sqlsrv:Server=' . DB_HOST . ';Database=' . DB_NAME);
            $connection->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);     //to capture error messages returned by db
            $this->setPdo($connection);
        }
        catch(\PDOException $e)
        {
            exit((DEBUGMODE) ? $e->getMessage() : 'There was a problem connecting to the database.');
        }
    }

    # generic query method - uses named placeholders for parameter binding
    private function query($sql, $parameters = [])
    {
        try
        {
            $this->setError(false);
            $stmt = $this->getPdo()->prepare($sql); //assign to a variable with a short name
            if ($stmt):             
                if (count($parameters)):
                    foreach($parameters as $name => $parameter):
                        $stmt->bindValue(':'.$name, $parameter);                        
                    endforeach;
                endif;              
                $stmt->execute();
                $this->setCount($stmt->rowCount());
                if ($stmt->rowCount() == -1):       //conditionally do the following if SQL stmt was a SELECT
                    $this->setResults($stmt->fetchAll(\PDO::FETCH_OBJ));
                    $this->setCount($stmt->rowCount()); //overwrite count attribute with number of rows returned by SELECT stmt
                endif;
            endif;
            return $this;
        }
        catch (\PDOException $e)
        {
            $this->setError(true);
            throw $e;
        }
    }

    // setter and getter methods for private variables not shown

}

编辑: 这是调用query()方法的代码。此方法也是DB类的一部分。

public function runQuery($operation, $sql, $parameters)
{       
    try
    {
        $this->query($sql, $parameters);                        //call query method all $operation types (read, write)
        if ($operation == 'read'):          
            if ($this->getCount()):
                if ($this->getCount() > 1):                     //for "read all"
                    $data = $this->getResults();
                else:                                           //for "read one"
                    $data = $this->getFirstResult();
                endif;
                $data = Arr::objectToArray($data);
                return $data;
            else:
                throw new \Exception("No data to display.");        //throw an exception if query runs fine but returns zero rows
            endif;
        endif;
    }
    catch (\PDOException $e)
    {
        throw (DEBUGMODE) ? $e : new \Exception("A database error occurred.  The $operation operation failed.");
    }
}

1 个答案:

答案 0 :(得分:0)

该问题原来是在调用方法中缺少反斜杠。我在所有对DB类中的全局类的引用中都加了反斜杠,但在其他具有catch块的命名空间中的其他类中则没有反斜杠。

实际上有两种方法可以解决此问题。
一种方法是将catch (Exception $e)更改为catch (\Exception $e)
或者,在整个代码中都按原样保留catch (Exception $e),并在命名空间声明之后和类定义起作用之前添加use \Exception;