【问题标题】:Non-Object Errors using PHP PDO with MySQL使用 PHP PDO 和 MySQL 的非对象错误
【发布时间】:2013-02-24 04:40:37
【问题描述】:

我已经为此苦苦思索了几天,但仍然无处可去。 我正在尝试通过 PHP PDO 从 MySQL 数据库中提取一小组值;我知道 PDO 的工作原理是我在其他地方使用它时的工作原理,并且我的代码基于以前工作的代码。

function custom_sub_cat_list($db_details, $cat_id) { //ln21
$subcat = NULL;
try {
    $h = new PDO("mysql:host=".$db_details['host'].";dbase=".$db_details['db'],$db_details['user'],$db_details['pass']);
    $h->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
} catch(PDOException $ex) {
    return false;
}
try {
    $q = $h->prepare("SELECT category FROM :tbl WHERE parentid = :catid;");
    $q->bindValue(":tbl", $db_details['tbl'], PDO::PARAM_STR);
    $q->bindValue(':catid', $cat_id, PDO::PARAM_STR);
    $q->execute();
    while($row = $_query->fetch()) {
        $subcat['id'][] = $row['categoryid'];
        $subcat['name'][] = $row['category'];
    };
    return $subcat;
} catch(PDOException $ex) {
    return false;
}
}//ln49

我在 bindValue 上得到“调用非对象上的成员函数 bindValue()”,并被如下调用。

$cat_id     = 123;
$db_details = array(
    "host"  => $sql_host,
    "db"    => $sql_db,
    "user"  => $sql_user,
    "pass"  => $sql_password,
    "tbl"   => $sql_tbl['categories']
);
custom_sub_cat_list ($db_details, $cat_id)

我确信这很明显,但我看不出问题所在,想要一双新的眼睛。

以下工作版本

非常感谢您!对于所有帮助过的人,我也学到了一些东西 :-) 那里有一些我忽略的愚蠢错误,我只是责怪看了两天扎实。

function custom_sub_cat_list($db_details, $cat_id) {
$subcat = NULL;
try {
    $h = new PDO("mysql:host=".$db_details['host'].";dbname=".$db_details['db'].";charset=utf8",$db_details['user'],$db_details['pass']);
    $h->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    $h->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $q = $h->prepare("SELECT category, categoryid FROM ".$db_details['table']." WHERE parentid = :cid;");
    $q->bindParam(':cid', $cat_id, PDO::PARAM_INT);
    $q->execute();
    while($row = $q->fetch()) {
        $subcat['id'][] = $row['categoryid'];
        $subcat['name'][] = $row['category'];
    };
    $h = NULL;
    return $subcat;
} catch(PDOException $ex) {
    print_r($ex->getMessage());
    print_r($ex->getTrace());
    //return false;
}
}

【问题讨论】:

标签: php mysql database pdo fatal-error


【解决方案1】:

你不需要一双新鲜的眼睛

您不是画家而是程序员(据说)。
因此,您必须运行它,而不是观看您的代码。并启用错误报告。

哦,刚刚发现它
当然,您不应该堵嘴错误消息!

} catch(PDOException $ex) {
    return false;
}

@ 运算符的现代版本。
请删除代码中的所有 try..catch 块,并仅在 learning what are they for. 之后开始使用它们

所以,为了解决这个问题以及未来的许多其他问题

  1. 删除代码中的所有 try..catch 块。
  2. 启用 PDO 的错误报告,如我在 cmets 中链接到的标记 wiki 中所述。
  3. 不要对标识符使用占位符,而是按照我链接到的标签 wiki 中的描述格式化它们
  4. 如果您不希望显示错误,请关闭 display_errors 设置(我能想到的抑制错误消息的唯一原因)。

此外,您不应在每个函数调用中打开单独的连接。
在脚本开头创建一个连接,然后在函数中使用 if,使用

global $h;

【讨论】:

  • 我是;我收到错误“PHP 致命错误:在第 31 行对非对象调用成员函数 bindValue()”
  • 即使没有 try..catch 它仍然有一个致命错误;错误消息被禁止显示是有原因的。
【解决方案2】:
$q = $h->prepare("SELECT category FROM :tbl WHERE parentid = :catid;");

您不能在 SQL 中为表名使用绑定参数。

当您尝试像这样准备无效的 SQL 语句时,prepare() 返回 false,而不是 PDOStatement 对象。

$q->bindValue(":tbl", $db_details['tbl'], PDO::PARAM_STR);

然后你尝试在 $q 上调用 bindValue() 方法,但是标量值 false 没有方法,所以这是一个致命错误。

您还试图捕获异常,但您没有配置 PDO 以在出错时抛出异常。因此 PDO 函数默认通过返回 false 来报告错误。

正如@Arkh 所示,您需要告诉 PDO 抛出异常:

$h->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

【讨论】:

    【解决方案3】:

    所以,你的错误告诉你 $q 不是一个对象。这意味着$h->prepare("SELECT category FROM :tbl WHERE parentid = :catid;"); 失败了。

    阅读PDO::prepare 文档时,您可以阅读以下内容:

    返回值

    如果数据库服务器成功准备语句,PDO::prepare() 返回一个 PDOStatement 对象。如果数据库服务器无法成功准备语句,则 PDO::prepare() 返回 FALSE 或发出 PDOException(取决于错误处理)。

    由于您没有设置 PDO 来抛出异常,您应该这样做以获得良好的错误消息或检查 $q 的值并获取最后报告的错误。 第一种方法:

    function custom_sub_cat_list($db_details, $cat_id) { //ln21
    $subcat = NULL;
    try {
        $h = new PDO("mysql:host=".$db_details['host'].";dbase=".$db_details['db'],$db_details['user'],$db_details['pass']);
        $h->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $h->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
        $q = $h->prepare("SELECT category FROM :tbl WHERE parentid = :catid;");
        $q->bindValue(":tbl", $db_details['tbl'], PDO::PARAM_STR);
        $q->bindValue(':catid', $cat_id, PDO::PARAM_STR);
        $q->execute();
        while($row = $_query->fetch()) {
            $subcat['id'][] = $row['categoryid'];
            $subcat['name'][] = $row['category'];
        };
        return $subcat;
    } catch(PDOException $ex) {
        echo $ex->getMessage();
        return false;
    }
    }//ln49
    

    这给出了错误:

    SQLSTATE[42000]:语法错误或访问冲突:1064 您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,以获取在 '? 附近使用的正确语法。哪里父母=?在第 1 行

    第二种方法:

    function custom_sub_cat_list($db_details, $cat_id) { //ln21
    $subcat = NULL;
        $h = new PDO("mysql:host=".$db_details['host'].";dbase=".$db_details['db'],$db_details['user'],$db_details['pass']);
        $h->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
        $q = $h->prepare("SELECT category FROM :tbl WHERE parentid = :catid;");
        if ($q === false) {
            print_r($h->errorInfo());
            return false;
        }
        $q->bindValue(":tbl", $db_details['tbl'], PDO::PARAM_STR);
        $q->bindValue(':catid', $cat_id, PDO::PARAM_STR);
        $q->execute();
        while($row = $_query->fetch()) {
            $subcat['id'][] = $row['categoryid'];
            $subcat['name'][] = $row['category'];
        };
        return $subcat;
    }//ln49
    

    结果:

    Array ( [0] => 42000 1 => 1064 [2] => 您的 SQL 语法有错误;请查看与您的 MySQL 服务器版本相对应的手册,以了解在 '? WHERE parentid = ?' 在第 1 行)

    您的问题是您不能为 :tbl (或 SQL 字符串的其他非值部分)使用绑定值。 所以你必须这样做:

    $q = $h->prepare("SELECT category FROM ".$db_details['tbl']." WHERE parentid = :catid;");
    

    【讨论】:

    • 1.永远不要使用 try catch 来显示错误。 2. 每个函数中的连接也是如此。 3. 标识符在添加到查询之前必须正确格式化。
    • 是的,try catch 应该用来做更有意义的事情。但我喜欢向人们解释如何解决他们遇到的第一个错误。好吧,错误消息很擅长。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-05
    • 1970-01-01
    • 1970-01-01
    • 2013-08-21
    • 2016-09-02
    • 1970-01-01
    相关资源
    最近更新 更多