【问题标题】:PDO in my own PHP Class我自己的 PHP 类中的 PDO
【发布时间】:2013-07-30 11:24:35
【问题描述】:

我是 PDO 的新手。我看了几个视频。我想像以前一样使用我自己的数据库类。我想使用 PDO 而不是 mysql* 函数。我知道 mysql* 函数在 PHP 5.5 中已被弃用

我没有处理我的旧数据库类。因为新手会更难。现在我只创建一个连接。我想选择我的产品。

这是我的代码:

class Database extends PDO {
    private $_server         = "localhost";
    private $_user           = "root";
    private $_password       = "";
    private $_db             = "demo";

    private $_engine = 'mysql';
    private $link = NULL;


    public function __construct() {
        $dsn = $this->_engine.':dbname='.$this->_db.';host='.$this->_server.';charset=utf8';

        try {
            $this->link = new PDO($dsn, $this->_user, $this->_password);
            $this->link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        } catch (PDOException $e) {
            echo 'Connection failed: ' . $e->getMessage();
        }
    }
}

header('Content-Type: text/html; charset=utf-8');
$DB = new Database();

$sql = "SELECT * FROM product";
$q  = $DB->query($sql);
while($r = $q->fetch(Database::FETCH_ASSOC)){
    $products[] = $r;
}

echo "<pre>";
print_r($products);
echo "</pre>";

我无法获取我的产品。我收到错误消息。

警告:PDO::query(): SQLSTATE[00000]: 无错误:在 /var/www/dt/includes/class/class.database.php 中未调用 PDO 构造函数 第 52 行

致命错误:在非对象上调用成员函数 fetch() /var/www/dt/includes/class/class.database.php 第 53 行

我的错误是什么?我该怎么办?

【问题讨论】:

  • 删除or die("Failed!") PDO 然后会抛出异常(因此PDO::ERRMODE_EXCEPTION)。使用此结果更新您的问题。
  • 我认为你不需要上课来使用 PDO,除非这是为了学习。
  • 您的类扩展了PDO,并且还在构造函数中实例化了一个新的 PDO 实例。这个新实例实际上并未设置为您创建的数据库对象中的属性。本质上,您的 Database 类实际上并没有创建到数据库的连接。使用parent::__construct($dsn, $this-&gt;user, $this-&gt;password); 而不是创建新的 PDO 实例。
  • 亲爱的@AlexP,我更新了我的问题。现在我收到内部服务器错误 500。
  • A 500 Internal Server Error 意味着您的脚本正在抛出错误,但您尚未配置 PHP 以显示错误消息。这是您在更进一步之前需要解决的问题;没有错误消息的帮助是不可能编码的。这是brief explanation

标签: php class pdo


【解决方案1】:

关于您的代码的一些随机想法。

滥用类继承

class Database extends PDO {
    private $link = NULL;

    public function __construct() {
            $this->link = new PDO($dsn, $this->_user, $this->_password);

Database 实例本身将是一个PDO 对象,因此在另一个 PDO 对象中包含一个 PDO 对象没有任何意义(其外部甚至无法正常工作,因为它尚未初始化)。你只需要这个:

class Database extends PDO {
    public function __construct() {
        parent::__construct($dsn, $this->_user, $this->_password);

未初始化的属性

public function __construct() {
    $dsn = $this->_engine.':dbname='.$this->_db.';host='.$this->_server.';charset=utf8';

所有这些$this-&gt; 变量来自哪里?您可能希望将它们作为构造函数参数传递。

中断错误处理

try {
    $this->link = new PDO($dsn, $this->_user, $this->_password);
    $this->link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
    echo 'Connection failed: ' . $e->getMessage();
}

您的类将连接错误降级为标准输出上的纯字符串。现在,无法记录或检测连接错误。

编辑:您询问如何检测或记录班级的连接错误。你可以做很多事情,但最简单的方法是……什么都不做。严重地。如果您只是从构造函数中删除 try/block,PDO 异常将自动冒泡,您将能够在任何需要的地方处理异常。例如:

try{
    $DB = new Database();
}catch(PDOException $e){
    // I want to handle connection errors in a special way
    // I'll log them here and I'll redirect the user to a static error page
    // That's something I couldn't do from the class constructor because I'd be missing context
}

...甚至:

try{
    $DB = new Database();
    $sql = "SELECT * FROM product";
    $q  = $DB->query($sql);
    while($r = $q->fetch(Database::FETCH_ASSOC)){
        $products[] = $r;
    }
}catch(Exception $e){
    // I prefer to handle all exceptions the same way, no matter the source
}

...但我会选择第一种方法:连接错误是您可以在生产中找到的唯一 PDOException 实例,而且您通常无能为力,因此给它们一个特殊的方法是有意义的治疗。

【讨论】:

  • 我正要向 OP 大喊滥用依赖项而不是注入它们(并解释 parent::),但这要好得多。
  • 如何更改我的班级以检测或记录连接错误。有什么想法吗?
  • @cihanblog - 查看我的编辑。请注意,这些只是想法。重要的是您了解这些技术并做出自己的明智决定:)
  • @ÁlvaroG.Vicario 感谢您的编辑。但我有点困惑。因为我有一个名为数据库的类。我创建了一个构造函数。在构造函数内部,我们使用了 PDO 构造。在这条线之后。我将使用 try/catch 块。但是你写了 $DB = new Database();你的意思是我会在自己内部使用数据库类?还是我理解错了?
  • @cihanblog - 这是你自己的代码。它不属于类代码,它是你实际使用类的方式。
【解决方案2】:

首先对错误报告进行排序。如果你想调试,你需要能够看到错误!

为此,您需要在php.ini 中编辑以下设置

error_reporting display_errors

确保在php.ini 文件中完成此操作(而不是在代码中使用ini_set()),然后重新启动服务器。

关于您的database abstraction,我看不出扩展PDO 类有什么真正的好处。一般来说,如果有的话,我只会扩展课程 父级中的一些我想重载的功能。

可能更有用的是通过将encapsulatePDO 实例的所有调用包装在您自己的自定义类中。这里的主要好处是 没有直接处理 PDO 实例的客户端代码,您可以更改或交换类的实现而不影响 其余代码。

一个人为的例子:

class Database
{
  protected $config = array();

  protected $pdo;

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

  protected function getPdo()
  {
    if (null == $this->pdo) {
      try {
        $config = $this->config;

        $dsn = $config['engine'].':dbname='.$config['database'].';host='.$config['host'].';charset=utf8';

        $this->pdo = new PDO($dsn, $config['user'], $config['password']);
        $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

      } catch (PDOException $e) {
        echo 'Connection failed: ' . $e->getMessage();
      }
    }
    return $this->pdo;
  }

  public function query($sql)
  {
    return $this->getPdo()->query($sql);
  }

}

$db = new Database(array(
  'engine' => 'mysql',
  'database' => 'databasename',
  'host' => 'localhost',
  'user' => 'fred',
  'password' => 'mypassword'
));
$results = $db->query('SELECT * FROM sometable');

【讨论】:

  • 当我尝试你的例子时。我得到了这个错误。注意:未定义的属性:第 40 行 /var/www/dt/includes/class/class.database.php 中的 Database::$_config 连接失败:找不到驱动程序致命错误:调用成员函数 query()第 56 行 /var/www/dt/includes/class/class.database.php 中的非对象
  • @cihanblog 修正了错字($this-&gt;_config 应该是$this-&gt;config)。它现在可以工作了,但是我只是想成为我试图解释的一个例子。
  • 谢谢。现在它正在工作。但是现在我没有决定扩展到 PDO 是更好的方法吗?还是你的方法更好?
  • 我们在这里创建的是proxy。代理对PDO 实例的所有调用的类。如果这比inheritance“更好”,一个很好的答案在这里:stackoverflow.com/questions/3965334/…
猜你喜欢
  • 2023-03-09
  • 2015-09-14
  • 1970-01-01
  • 2015-11-14
  • 2012-02-27
  • 1970-01-01
  • 2016-07-12
  • 2016-07-15
  • 1970-01-01
相关资源
最近更新 更多