-2

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

  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.");
    }
}
4

1 回答 1

0

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

实际上有两种不同的方法来解决这个问题。
一种方法是更改catch (Exception $e)​​为catch (\Exception $e).
或者,catch (Exception $e)在整个代码中保持原样并use \Exception;在命名空间声明之后和类定义之前添加也可以。

于 2019-02-13T04:21:59.457 回答