Php 如何在PDO包装器中返回execute的值

Php 如何在PDO包装器中返回execute的值,php,pdo,return,prepared-statement,Php,Pdo,Return,Prepared Statement,下面是我的PDO包装。我希望能够使用run方法,但是,我希望能够检查执行是否成功,例如: if($sth->execute()) { ... } 但是,正如您在包装器中看到的,run命令只返回prepare语句,实现这一点的最有效方法是什么 因为在成功时返回true/false,而当前的run方法在失败时返回PDOStatement。我建议检查prepare和execute是否为false,并在成功时返回PDO语句,否则返回false,就像PDO::prepare和PDO::query一样

下面是我的PDO包装。我希望能够使用
run
方法,但是,我希望能够检查执行是否成功,例如:

if($sth->execute())
{
...
}
但是,正如您在包装器中看到的,run命令只返回
prepare
语句,实现这一点的最有效方法是什么


因为在成功时返回true/false,而当前的
run
方法在失败时返回
PDOStatement
。我建议检查
prepare
execute
是否为false,并在成功时返回
PDO语句
,否则返回false,就像
PDO::prepare
PDO::query
一样

功能示例
另一种方法是将最后一个执行值存储在属性中,以便以后检索

例子
为了解决以下关于使用异常处理确定
PDO::execute
方法何时在
Database::run
方法中特别失败的问题的最佳实践注释

请记住,它们不是对的或错的,“它们只是编写代码的推荐方法。”指的是在专业应用程序开发中通常首选的编程方法。始终使用最适合您、您为之开发的环境和您的应用程序需求的工具

一般来说,StackOverlow不是讨论或评估作者的申请的合适场所 最佳做法。这些类型的讨论或评论应该保留给其他人。堆栈溢出是 旨在或提供一种可行的替代方法来实现用户的要求。不推断用户提出了错误的问题

要使用异常,您需要启用
PDO::ERRMODE\u异常
(请参见下面的
数据库
类)

try/catch
与PDO包装器方法一起使用的问题是,PDO只会抛出一个异常对象
PDOException
,这无法让您确定哪个PDO方法调用特别失败。让你去读手术室,去确定原因

一种简单的方法是检查引起异常的函数名的
PDOException::trace

功能示例(PHP 5.6+): 请参见by上的答案,以了解对
PDOException
处理

上述方法防止您仅处理
Database::run
方法中的特定异常类型,要求您使用
throw$e在您的条件之后,当异常意外时。
为了解决这个问题,另一种方法是创建自定义异常类。您可以通过扩展基本的
PDOException
类来实现这一点,使其与其他异常处理方法兼容或捕获其中的任何一种

为了捕获任何
run
特定异常,可以使用空接口,然后在扩展的
PDOException
类上实现该接口

interface DatabaseRunException{}
然后为要处理的每个特定PDO方法创建一个新的异常类,该类实现了
DatabaseRunException
接口

class PDOPrepareException extends PDOException implements DatabaseRunException{}

class PDOExecuteException extends PDOException implements DatabaseRunException{}

class PDOQueryException extends PDOException implements DatabaseRunException{}
要使用自定义异常来确定哪个PDO方法失败,您需要在
数据库::run()
方法中处理
PDO异常
,并
抛出其中一个自定义异常。

为了简洁起见,我删除了某些部分,注释掉了可能会改变当前配置的内容,对PHP5.6+进行了一些最佳实践和优化更改

class Database 
{

    private const OPTIONS = [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        // PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ,
        // PDO::ATTR_EMULATE_PREPARES => false
    ];

    //...

    protected function __construct()
    {
        $this->pdo = new PDO($dsn, self::user, self::password, self::OPTIONS);
    }

    public static function instance()
    {
        if (null === self::$instance) {
            self::$instance = new self;
        }

        return self::$instance;
    }

    public function __call($method, $args)
    {
        //always ensure the desired method is callable!
        if (is_callable([$this->pdo, $method])) {
            //php 5.6+ variadic optimization (aka splat operator)
            return $this->pdo->$method(...$args);

            //php <= 5.5
            //return call_user_func_array(array($this->pdo, $method), $args);
        }
        throw new \BadMethodCallException(sprintf('Unknown method PDO::%s called!', $method));
    }

    public function run($sql, $args = [])
    {
        if (!$args) {
            try {
                return $this->query($sql);
            } catch(\PDOException $e) {
                 throw new \PDOQueryException($e->getMessage(), (int) $e->getCode(), $e);
            }
        }
        try {
            $stmt = $this->prepare($sql);
        } catch(\PDOException $e) {
            throw new \PDOPrepareException($e->getMessage(), (int) $e->getCode(), $e);
        }
        try {
            $stmt->execute($args);

            return $stmt;
        } catch(\PDOException $e) {
            throw new \PDOExecuteException($e->getMessage(), (int) $e->getCode(), $e);
        }

        throw new \LogicException('Unknown error occurred');
    }

}
在PHP7.1+中,您可以捕获多个异常

try {
   $db = Database::instance();
   $db->run('SELECT ?', ['foo', 'bar']);
} catch(\PDOQueryException $e) {
    //Handle the query exception
    throw $e;
} catch(\PDOPrepareException $e) {
    //Handle the prepare exception
    throw $e;
} catch(\PDOExecuteException $e) {
    echo 'PDO::execute() failed';
    //Handle the execute exception
    throw $e;
}
在PHPSince中,返回true/false,当前的
run
方法在成功时返回
PDOStatement
,在失败时返回false。我建议检查
prepare
execute
是否为false,并在成功时返回
PDO语句
,否则返回false,就像
PDO::prepare
PDO::query
一样

功能示例
另一种方法是将最后一个执行值存储在属性中,以便以后检索

例子
为了解决以下关于使用异常处理确定
PDO::execute
方法何时在
Database::run
方法中特别失败的问题的最佳实践注释

请记住,它们不是对的或错的,“它们只是编写代码的推荐方法。”指的是在专业应用程序开发中通常首选的编程方法。始终使用最适合您、您为之开发的环境和您的应用程序需求的工具

一般来说,StackOverlow不是讨论或评估作者的申请的合适场所 最佳做法。这些类型的讨论或评论应该保留给其他人。堆栈溢出是 旨在或提供一种可行的替代方法来实现用户的要求。不推断用户提出了错误的问题

要使用异常,您需要启用
PDO::ERRMODE\u异常
(请参见下面的
数据库
类)

try/catch
与PDO包装器方法一起使用的问题是,PDO只会抛出一个异常对象
PDOException
,这无法让您确定哪个PDO方法调用特别失败。让你去读手术室,去确定原因

一种简单的方法是检查引起异常的函数名的
PDOException::trace

功能示例(PHP 5.6+): 关于
p的更一般化方法,请参见by上的答案
try {
   $db = Database::instance();
   var_dump($db->run('SELECT ?', ['foo', 'bar'])->fetch());
} catch(\PDOException $e) {
   if ('execute' === $e->getTrace()[0]['function']) {
       echo 'PDO::execute() failed';
       //Handle the execute exception
   }
   throw $e;
}
interface DatabaseRunException{}
class PDOPrepareException extends PDOException implements DatabaseRunException{}

class PDOExecuteException extends PDOException implements DatabaseRunException{}

class PDOQueryException extends PDOException implements DatabaseRunException{}
class Database 
{

    private const OPTIONS = [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        // PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ,
        // PDO::ATTR_EMULATE_PREPARES => false
    ];

    //...

    protected function __construct()
    {
        $this->pdo = new PDO($dsn, self::user, self::password, self::OPTIONS);
    }

    public static function instance()
    {
        if (null === self::$instance) {
            self::$instance = new self;
        }

        return self::$instance;
    }

    public function __call($method, $args)
    {
        //always ensure the desired method is callable!
        if (is_callable([$this->pdo, $method])) {
            //php 5.6+ variadic optimization (aka splat operator)
            return $this->pdo->$method(...$args);

            //php <= 5.5
            //return call_user_func_array(array($this->pdo, $method), $args);
        }
        throw new \BadMethodCallException(sprintf('Unknown method PDO::%s called!', $method));
    }

    public function run($sql, $args = [])
    {
        if (!$args) {
            try {
                return $this->query($sql);
            } catch(\PDOException $e) {
                 throw new \PDOQueryException($e->getMessage(), (int) $e->getCode(), $e);
            }
        }
        try {
            $stmt = $this->prepare($sql);
        } catch(\PDOException $e) {
            throw new \PDOPrepareException($e->getMessage(), (int) $e->getCode(), $e);
        }
        try {
            $stmt->execute($args);

            return $stmt;
        } catch(\PDOException $e) {
            throw new \PDOExecuteException($e->getMessage(), (int) $e->getCode(), $e);
        }

        throw new \LogicException('Unknown error occurred');
    }

}
try {
   $db = Database::instance();
   $db->run('SELECT ?', ['foo', 'bar']);
} catch(\PDOExecuteException $e) {
    echo 'PDO::execute() failed';
    //Handle the execute exception
    throw $e;
}
try {
   $db = Database::instance();
   $db->run('SELECT ?', ['foo', 'bar']);
} catch(\PDOQueryException $e) {
    //Handle the query exception
    throw $e;
} catch(\PDOPrepareException $e) {
    //Handle the prepare exception
    throw $e;
} catch(\PDOExecuteException $e) {
    echo 'PDO::execute() failed';
    //Handle the execute exception
    throw $e;
}
try {
   $db = Database::instance();
   $db->run('SELECT ?', ['foo', 'bar']);
} catch(\DatabaseRunException $e) {
    if ($e instanceof \PDOQueryException) {
       //Handle the query exception
    } elseif ($e instanceof \PDOPrepareException) {
       //Handle the prepare exception
    } elseif ($e instanceof \PDOExecuteException) {
       echo 'PDO::execute() failed';
       //Handle the execute exception
    }
    throw $e;
}
try {
  throw new \Exception('FooBar');
  $foo = 'foo';
} catch(\Exception $e) {
   var_dump(isset($foo)); //false
}
var_dump(isset($foo)); //false