基于OOP重构PDO登录表单时遇num_rows非对象错误求助
兄弟,这个错误我遇过好多次了,本质上要么是你把PDO和mysqli的用法搞混了,要么就是你的查询执行失败返回了false,导致你试图访问一个非对象的属性。咱们一步步来解决:
1. 先搞懂错误根源
num_rows是mysqli结果集对象的专属属性,但PDO的查询结果是PDOStatement对象,它根本没有这个属性!如果你在canilogin函数里写了类似$stmt->num_rows的代码,那百分百是这里出问题了。
另外,如果你的PDO查询(比如prepare或execute)因为SQL语法错误、数据库连接失败等问题返回了false,而非有效的PDOStatement对象,这时候你去访问num_rows自然会触发这个Notice。
2. 修正PDO的行数获取方式
PDO里要获取查询结果的行数,得用rowCount()方法,而不是num_rows。比如把错误的写法:
// ❌ 错误:PDO没有num_rows属性 if ($stmt->num_rows > 0) { ... }
改成:
// ✅ 正确的PDO行数获取 $stmt->execute([$username]); $totalUsers = $stmt->rowCount(); if ($totalUsers > 0) { ... }
不过更高效的做法是直接获取用户数据,不用单独统计行数——毕竟我们要的是用户信息来验证密码,比如:
$user = $stmt->fetch(PDO::FETCH_ASSOC); if ($user) { // 用户存在,继续验证密码 }
3. 给PDO加上错误提示,快速排查问题
建议你在初始化PDO连接的时候开启异常错误模式,这样如果查询出问题,会直接抛出异常告诉你哪里错了,比瞎猜强多了:
// 初始化PDO连接时添加这行 $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
4. 完整的canilogin函数参考(PDO正确写法)
给你一个靠谱的实现示例,包含密码验证(假设密码是用password_hash存储的,这也是PHP官方推荐的安全做法):
function canilogin($username, $password) { // 这里假设你已经有全局的PDO连接,或者在函数内初始化连接 global $pdo; try { // 只查询需要的字段(id和密码,不要查所有字段) $stmt = $pdo->prepare("SELECT id, password FROM users WHERE email = ?"); // 绑定参数,防止SQL注入 $stmt->execute([$username]); // 获取用户数据 $user = $stmt->fetch(PDO::FETCH_ASSOC); // 验证用户存在且密码正确 if ($user && password_verify($password, $user['password'])) { // 这里可以设置登录session,比如: $_SESSION['user_id'] = $user['id']; return true; } return false; } catch (PDOException $e) { // 调试阶段可以输出错误,上线后换成日志记录 error_log("登录查询错误: " . $e->getMessage()); return false; } }
5. 最后检查login.php的调用
确保你在login.php里的$_POST键名和表单一致(你代码里用的email和password,只要表单里的input name也是这两个就没问题),而且调用canilogin时参数顺序正确。
按照上面的步骤改完,这个Notice应该就消失了,而且你的PDO登录逻辑也会更健壮。
内容的提问来源于stack exchange,提问作者Zanic L3

