连接PDO出现问题

4

这是我第一次使用PDO进行测试。但是出现了一个奇怪的错误,经过谷歌搜索,发现这个错误很奇怪。

以下是我的数据库测试类:

class db extends PDO
{
    # Our instance.
    private static $db = NULL;

    # Calling the connector.
    public static function connect()
    {
        if (self::$db === NULL)
        {
            $class = __CLASS__;
            self::$db = new $class();
        }
        return self::$db;
    }

    # Connector.
    public function __construct() 
    { 
        $dns = 'mysql:dbname='.reg::get('db-name').';host='.reg::get('db-host');
        self::$db = new PDO($dns, reg::get('db-username'), reg::get('db-password'));
        reg::delete('db-password');
    }

    # Quick reporting
    public function reportError($array)
    {
        if ($this->db != NULL) { echo 'Myself getting horny'; } // Just for testing, i'm not getting horny because of a mysql database connection!
    }

}

那么执行以下代码:

$db = new db();
$row = $db->prepare('SELECT * FROM test WHERE id = :id')->execute(array('id' => 1));
echo $row['value'];

它向我显示以下错误:
Warning: PDO::prepare() [pdo.prepare]: SQLSTATE[00000]: No error: PDO constructor was not called in myfile.php on line 39

将第39行视为

$row = $db->prepare('SELECT * FROM test WHERE id = :id')->execute(array('id' => 1));

@andre matos,是的,我做了。完全相同的错误出现了。 - Shoe
为什么要有connect方法?为什么要检查$db是否为空而不是self::$db?为什么要执行self::$db = new db(); - Alix Axel
目前不是你的问题,但是你不能在表格/列名中使用占位符。只能用于计算出一个值的东西。 - goat
4个回答

5
你的代码很混乱,可能是因为你太兴奋了... connect() 方法 - 为什么需要它?
if ($db === NULL)

should be:

if (self::$db === NULL)

self::$db = new $class();

所以,如果 $class == __CLASS__ == db,那么使用 self::$db = new db(); 是不正确的。
你不能使用PDO来准备标识符,例如表格或列。
$db->prepare('SELECT * FROM :table WHERE id = :id')->execute(array('table' => 'test', 'id' => 1));

应该是:

$db->prepare('SELECT * FROM `test` WHERE id = :id')->execute(array('id' => 1));

尝试这个:
class db extends PDO
{
    private static $db = null;

    public static function singleton()
    {
        if (is_null(self::$db) === true)
        {
            self::$db = new PDO('mysql:dbname='.reg::get('db-name').';host='.reg::get('db-host'), reg::get('db-username'), reg::get('db-password'));
        }

        return self::$db;
    }
}

像这样:

$result = db::singleton()->prepare('SELECT * FROM `test` WHERE id = :id')->execute(array('id' => 1));

var_dump($result);

我已经进行了更正,但仍然出现错误。另外,我应该如何能够使用所有PDO方法,并且每次想要调用db::singleton()/db::connect()获取数据库单例实例? - Shoe
@Charlie Pigarelli:PS,你其实不需要一个类来实现这个,一个简单的函数也可以达到同样的效果:function singleton() { static $db = null; if (is_null($db)) { $db = new PDO(/*...*/); } return $db; } - Alix Axel
尝试过了,但是没有显示任何东西。即使我使用var_dump()打印$result也没有输出。 - Shoe
@Charlie Pigarelli:奇怪。尝试在脚本顶部添加以下内容启用错误报告:error_reporting(-1); ini_set('display_errors', 1);。此外,reg类是否已定义?reg::get()方法是否定义为静态并返回某些内容?尝试使用有效值替换reg::get()调用,然后再次尝试。 - Alix Axel
嗯,嗯,我自己找到了空白页面的错误,它与这个问题无关。我重新尝试了你的代码,返回了'bool(true)',这意味着它正常工作。谢谢。在接受答案之前还有一个问题:为什么$result = db::singleton()->prepare('SELECT value FROM test WHERE id = :id')->execute(array('id' => 1))->fetch();没能生效? - Shoe
@Charlie Pigarelli:因为execute()方法只返回true或false,而fetch() - 就像fetchAll()一样作用于PDOStatement对象。你需要这样做:$result = db::singleton()->prepare('...'); $result->execute('...'); print_r($result->fetch()); - Alix Axel

2

我不确定这是否是你要的答案,因为它似乎与错误消息无关,但我认为你不能将表名作为绑定参数传递。如果你在:table的位置上放置一个硬编码的表名,会发生什么?


1
你有一个静态的 'connect' 构造函数,它在静态中创建一个 db-object,并返回它。但你也自己创建了一个新的 db()。
准备语句使用 self::$db,因此尝试调用静态生成的变量。我不太确定你的代码应该如何工作,结合某种单例/静态形式和对象形式。
但那似乎就是问题所在。

等一下,我们不能将db::getInstance() (<- 单例模式?) 和对象形式结合起来吗? - Shoe

1

你的单例模式写得完全错误。你的构造函数应该是private,并且你应该使用静态实例$db。请参考这个单例模式示例


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接