我的申请中有以下课程:
<?php
class Connection extends Mysqli{
public function __construct($mysqli_host,$mysqli_user,$mysqli_pass, $mysqli_db) {
parent::__construct($mysqli_host,$mysqli_user,$mysqli_pass,$mysqli_db);
$this->throwConnectionExceptionOnConnectionError();
}
private function throwConnectionExceptionOnConnectionError(){
if(!$this->connect_error){
echo "Database connection established<br/>";
}else{
//$message = sprintf('(%s) %s', $this->connect_errno, $this->connect_error);
echo "Error connecting to the database.";
throw new DatabaseException($message);
}
}
}
class DatabaseException extends Exception
{
}
class Page extends Mysqli{
private $con;
public function __construct(Connection $con) {
$this->con = $con;
if(isset($_GET['id'])){
$id = $_GET['id'];
}else{
$id = 1;
}
$this->get_headers($id);
$this->get_content($id);
$this->get_footer($id);
}
private function get_headers($pageId){
$retrieveHead = $this->con->prepare("SELECT headers FROM pages WHERE page_id=?");
$retrieveHead->bind_param('i',$pageId);
$retrieveHead->execute();
$retrieveHead->bind_result($header);
$retrieveHead->fetch();
$retrieveHead->close();
echo $header;
}
private function get_footer($pageId){
$retrieveFooter = $this->con->prepare("SELECT footer FROM pages WHERE page_id=?");
$retrieveFooter->bind_param('i',$pageId);
$retrieveFooter->execute();
$retrieveFooter->bind_result($footer);
$retrieveFooter->fetch();
$retrieveFooter->close();
echo $footer;
}
private function get_content($pageId){
$retreiveContent = $this->con->prepare("SELECT template_id, section_title, i1, i2 FROM content WHERE page_id=? ORDER BY sequence DESC");
$retreiveContent->bind_param('i',$pageId);
$retreiveContent->execute();
$retreiveContent->bind_result($template_id, $section_title, $i1, $i2);
while ($retreiveContent->fetch()) {
//Variables will be populated for this row.
//Update the tags in the template.
$template = $this->get_template($template_id);
$template = str_replace('[i1]',$i1,$template);
$template = str_replace('[i2]',$i2,$template);
//$theTemplate is populated with content. Probably want to echo here
echo $template;
}
}
private function get_template($template_id){
$retreiveTemplate = $this->con->prepare("SELECT code FROM templates WHERE template_id=?");
$retreiveTemplate->bind_param('i',$template_id);
$retreiveTemplate->execute();
$retreiveTemplate->bind_result($template);
$retreiveTemplate->fetch();
$retreiveTemplate->close();
return $template;
}
}
?>
小应用程序应该基本上从URL获取页面变量,并使用它来拉出页面的页眉,内容项和页脚,内容项使用也从数据库中检索的模板呈现。运行包含以下代码的索引文件时:
require ("/req/db_connection.php");
require ("/req/connection.php");
$dbConnection = new Connection($mysqli_host,$mysqli_user,$mysqli_pass, $mysqli_db);
$page = new Page();
我得到以下输出:
Database connection established
Warning: mysqli::prepare(): Couldn't fetch Page in C:\xampp\htdocs\forum\req\connection.php on line 39
Fatal error: Call to a member function bind_param() on a non-object in C:\xampp\htdocs\forum\req\connection.php on line 40
对于我遇到这些错误的原因,有没有人能指出正确的方向?
第39行是以下声明:
$retrieveHead = $this->prepare("SELECT headers FROM pages WHERE page_id=?");
第40行当然是:
$retrieveHead->bind_param('i',$pageId);
非常感谢任何帮助。
N.B。上面的代码现在已经根据下面的答案进行了更正,但是我仍然在第80行遇到以下错误:
Call to a member function bind_param() on a non-object in C:\xampp\htdocs\forum\req\connection.php on line 80
这一行:
$retreiveTemplate->bind_param('i',$template_id);
有什么建议吗?
答案 0 :(得分:3)
class Page extends Mysqli{
public function __construct() {
if(isset($_GET['id'])){
$id = $_GET['id'];
}else{
$id = 1;
}
$this->get_headers($id);
$this->get_content($id);
$this->get_footer($id);
}
上面的代码看起来像是问题(等等)。你扩展mysqli,覆盖构造函数,不要调用父构造函数。因此,没有调用任何基本的mysqli构造函数例程,并且没有任何连接。考虑重新设计对象并将它们传递给Connection
对象,而不是将mysqli扩展到任何地方。我也会尽量避免在构造函数中完成所有工作。例如,您的页面类可能类似于:
class Page{
private $con;
public function __construct(Connection $con) {
$this->con = $con;
}
public function get_headers($pageId){
$retrieveHead = $this->conn->prepare("SELECT headers FROM pages WHERE page_id=?");
//...
}
}
当我打趣“除其他人之外”(没有沮丧意图)上面我暗示 - 虽然你的错误的实际原因是构造函数 - 在你的类和OOP概念的设计中看起来有些混乱一般来说。
class Connection extends Mysqli{
public function __construct($mysqli_host,$mysqli_user,$mysqli_pass, $mysqli_db) {
parent::__construct($mysqli_host,$mysqli_user,$mysqli_pass,$mysqli_db);
$this->throwConnectionExceptionOnConnectionError();
}
}
在这里,您已使用mysqli
类扩展Connection
,并正确调用父构造函数并传递所有必需参数以建立连接。如果您实例化此类型的对象$myConnection = new Connection(...)
,它可以充当您的数据库网关。
Page
等其他类可能需要对数据库执行操作,他们可以通过Connection
执行操作,而不是通过扩展mysqli
本身。您可以在Connection
构造函数中传递Page
的实例来实现此目的。所以你的代码行在这里:
$dbConnection = new Connection($mysqli_host,$mysqli_user,$mysqli_pass, $mysqli_db);
$page = new Page();
将成为(在对如上所示的Page类进行一些修改之后):
$dbConnection = new Connection($mysqli_host,$mysqli_user,$mysqli_pass, $mysqli_db);
$page = new Page($dbConnection);
答案 1 :(得分:1)
此错误消息显示,因为在尝试准备语句时尚未建立与数据库服务器的连接。更短的重现代码:
class Page extends Mysqli{
public function __construct(){
$this->prepare('SELECT CURRENT_TIMESTAMP');
}
}
new Page;
在mysql对象中,连接是在constructor中建立的,但是你覆盖了这样的构造函数,从不调用父对象。
恕我直言,页面是数据库对象的实例是没有意义的。您只需在需要时提供DB对象作为参数。<强>更新强>
您可以在每次需要时传递数据库对象:
class Page{
public function foo(Mysqli $db){
$db->prepare('SELECT CURRENT_TIMESTAMP');
}
}
...或存储以供日后使用:
class Page{
protected $db;
public function __construct(Mysqli $db){
$this->db = $db;
}
public function foo(){
$this->db->prepare('SELECT CURRENT_TIMESTAMP');
}
}
如果您扩展Mysqli
,请使用正确的类名作为类型提示:
public function foo(Connection $db){
}
还有其他解决方案,比如接口,但它太复杂了。)