$pdo returns 实施路由器后方法中的 NULL
$pdo returns NULL from a method after implementing a router
我花了几个小时试图解决这个问题。
我的网站运行良好,但我需要更改一些难看的 URL。
我尝试实现一个路由器 (AltoRouter),经过一些更改后一切正常,直到出现此错误:
Fatal error: Uncaught Error: Call to a member function prepare() on null in foldername line X
我有一个基本的 MVC,模型如下所示:
基本上$pdo在这个方法中是空的:
(还有那个 class 中的每一个方法)
class UsersModel {
public function confirmedUser($username) {
global $pdo;
$sql = "SELECT * FROM users WHERE username = ? AND confirmed_at IS NOT NULL";
$request = $pdo->prepare($sql); // Fatal error here
$request->execute([$username]);
return $request->fetch();
}
}
控制器看起来像这样:
<?php
require_once "../php/connect.php";
require_once "../models/UsersModel.class.php";
$usersModel = new UsersModel();
if(array_key_exists('register', $_POST) && !empty($_POST)) {
$username = $_POST['username'];
$email = $_POST['email'];
$password = $_POST['password'];
$passwordConfirm = $_POST['passwordConfirm'];
$usersModel->checkName($username);
$usersModel->checkEmail($email);
$usersModel->checkPassword($password, $passwordConfirm);
}
我的连接文件:
<?php
const DBNAME = "imparfait";
const DBUSER = "root";
const DBPASS = "";
$pdo = new PDO('mysql:host=localhost;dbname='.DBNAME.';charset=utf8', DBUSER, DBPASS);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
路由器看起来像这样:
(有点凌乱的自动取款机)
$router = new AltoRouter();
// map routes
$router->map('GET', '/', 'home', 'Home');
$router->map('GET', '/contact', 'contact', 'Contact');
$router->map('GET', '/about', 'about', 'About');
$router->map('GET', '/[*:slug]/[i:id]', 'article', 'Article');
$router->map('GET', '/login', function() {
require './controller/users/login.php';
}, 'Login');
$router->map( 'POST', '/login', function() {
require './controller/users/login.php';
});
$router->map('GET', '/forgot-password', function() {
require './controller/users/forgotPassword.php';
}, 'Forgot');
$router->map( 'POST', '/forgot-password', function() {
require './controller/users/forgotPassword.php';
});
$router->map('GET', '/logout', 'logout', 'Logout');
$router->map('GET', '/register', function() {
require './controller/users/register.php';
}, 'Register');
$router->map( 'POST', '/register', function() {
require './controller/users/register.php';
});
$router->map('GET', '/account', function() {
require './controller/users/account.php';
}, 'Account');
$match = $router->match();
// call closure or throw 404 status
if(is_array($match)) {
require './views/inc/header.phtml';
if (is_callable( $match['target'])) {
call_user_func_array( $match['target'], $match['params'] );
} else {
$params = $match['params'];
require "./controller/{$match['target']}.php";
}
require './views/inc/footer.phtml';
} else {
// no route was matched
header( $_SERVER["SERVER_PROTOCOL"] . ' 404 Not Found');
require './views/404.php';
}
我查看了堆栈溢出,但每个 post 都与数据库对象相关。
我不明白在实施路由器后什么会影响 $pdo 的值。
我需要创建一个 class 来解决这个问题吗?
感谢任何帮助。
@AbraCadaver 已经向您解释了原因,您遇到指定问题的原因。所以,在这方面,功劳都归于他。
请注意,在 MVC 应用程序的正确实现中,数据库连接仅由 model layer 的组件使用。
因此,考虑到您当前的设计,正确的解决方案是将 $pdo
实例传递给每个 model 在匹配路由的范围内创建的对象 目标.
因此,UsersModel
应该接收 $pdo
作为依赖项:
class UsersModel {
/**
* Database connection.
*
* @var \PDO
*/
private $connection;
/**
* @param PDO $connection Database connection.
*/
public function __construct(\PDO $connection) {
$this->connection = $connection;
}
public function confirmedUser($username) {
// ...Please, no global variables anymore!...
$sql = 'SELECT *
FROM users
WHERE
username = :username AND
confirmed_at IS NOT NULL';
$statement = $this->connection->prepare($sql);
$statement->execute([
':username' => $username,
]);
$data = $statement->fetch(PDO::FETCH_ASSOC);
/*
* As I recall, PDOStatement::fetch returns FALSE when no records are found - instead of
* an empty array, like PDOStatement::fetch returns. But, in terms of PDO, a returned
* FALSE means "failure" and triggers an exception.
* So I handle this "special" situation here.
*/
return ($data === false) ? [] : $data;
}
}
控制器(如path-to/controller/users/register.php
)然后必须将$pdo
对象传递给新创建的UsersModel
实例(参见Dependency injection):
<?php
require_once '../php/connect.php';
require_once '../models/UsersModel.class.php';
$usersModel = new UsersModel($pdo);
if(/*...*/) {
//...
$usersModel->confirmedUser($username);
}
建议:在包含创建数据库连接的文件时始终使用 require
而不是 require_once
:
require "../php/connect.php";
我花了几个小时试图解决这个问题。 我的网站运行良好,但我需要更改一些难看的 URL。
我尝试实现一个路由器 (AltoRouter),经过一些更改后一切正常,直到出现此错误:
Fatal error: Uncaught Error: Call to a member function prepare() on null in foldername line X
我有一个基本的 MVC,模型如下所示:
基本上$pdo在这个方法中是空的: (还有那个 class 中的每一个方法)
class UsersModel {
public function confirmedUser($username) {
global $pdo;
$sql = "SELECT * FROM users WHERE username = ? AND confirmed_at IS NOT NULL";
$request = $pdo->prepare($sql); // Fatal error here
$request->execute([$username]);
return $request->fetch();
}
}
控制器看起来像这样:
<?php
require_once "../php/connect.php";
require_once "../models/UsersModel.class.php";
$usersModel = new UsersModel();
if(array_key_exists('register', $_POST) && !empty($_POST)) {
$username = $_POST['username'];
$email = $_POST['email'];
$password = $_POST['password'];
$passwordConfirm = $_POST['passwordConfirm'];
$usersModel->checkName($username);
$usersModel->checkEmail($email);
$usersModel->checkPassword($password, $passwordConfirm);
}
我的连接文件:
<?php
const DBNAME = "imparfait";
const DBUSER = "root";
const DBPASS = "";
$pdo = new PDO('mysql:host=localhost;dbname='.DBNAME.';charset=utf8', DBUSER, DBPASS);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
路由器看起来像这样: (有点凌乱的自动取款机)
$router = new AltoRouter();
// map routes
$router->map('GET', '/', 'home', 'Home');
$router->map('GET', '/contact', 'contact', 'Contact');
$router->map('GET', '/about', 'about', 'About');
$router->map('GET', '/[*:slug]/[i:id]', 'article', 'Article');
$router->map('GET', '/login', function() {
require './controller/users/login.php';
}, 'Login');
$router->map( 'POST', '/login', function() {
require './controller/users/login.php';
});
$router->map('GET', '/forgot-password', function() {
require './controller/users/forgotPassword.php';
}, 'Forgot');
$router->map( 'POST', '/forgot-password', function() {
require './controller/users/forgotPassword.php';
});
$router->map('GET', '/logout', 'logout', 'Logout');
$router->map('GET', '/register', function() {
require './controller/users/register.php';
}, 'Register');
$router->map( 'POST', '/register', function() {
require './controller/users/register.php';
});
$router->map('GET', '/account', function() {
require './controller/users/account.php';
}, 'Account');
$match = $router->match();
// call closure or throw 404 status
if(is_array($match)) {
require './views/inc/header.phtml';
if (is_callable( $match['target'])) {
call_user_func_array( $match['target'], $match['params'] );
} else {
$params = $match['params'];
require "./controller/{$match['target']}.php";
}
require './views/inc/footer.phtml';
} else {
// no route was matched
header( $_SERVER["SERVER_PROTOCOL"] . ' 404 Not Found');
require './views/404.php';
}
我查看了堆栈溢出,但每个 post 都与数据库对象相关。
我不明白在实施路由器后什么会影响 $pdo 的值。 我需要创建一个 class 来解决这个问题吗?
感谢任何帮助。
@AbraCadaver 已经向您解释了原因,您遇到指定问题的原因。所以,在这方面,功劳都归于他。
请注意,在 MVC 应用程序的正确实现中,数据库连接仅由 model layer 的组件使用。
因此,考虑到您当前的设计,正确的解决方案是将 $pdo
实例传递给每个 model 在匹配路由的范围内创建的对象 目标.
因此,UsersModel
应该接收 $pdo
作为依赖项:
class UsersModel {
/**
* Database connection.
*
* @var \PDO
*/
private $connection;
/**
* @param PDO $connection Database connection.
*/
public function __construct(\PDO $connection) {
$this->connection = $connection;
}
public function confirmedUser($username) {
// ...Please, no global variables anymore!...
$sql = 'SELECT *
FROM users
WHERE
username = :username AND
confirmed_at IS NOT NULL';
$statement = $this->connection->prepare($sql);
$statement->execute([
':username' => $username,
]);
$data = $statement->fetch(PDO::FETCH_ASSOC);
/*
* As I recall, PDOStatement::fetch returns FALSE when no records are found - instead of
* an empty array, like PDOStatement::fetch returns. But, in terms of PDO, a returned
* FALSE means "failure" and triggers an exception.
* So I handle this "special" situation here.
*/
return ($data === false) ? [] : $data;
}
}
控制器(如path-to/controller/users/register.php
)然后必须将$pdo
对象传递给新创建的UsersModel
实例(参见Dependency injection):
<?php
require_once '../php/connect.php';
require_once '../models/UsersModel.class.php';
$usersModel = new UsersModel($pdo);
if(/*...*/) {
//...
$usersModel->confirmedUser($username);
}
建议:在包含创建数据库连接的文件时始终使用 require
而不是 require_once
:
require "../php/connect.php";