-1

我的应用程序中有以下类:

    <?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);

任何帮助将不胜感激。

注意上面的代码现在已经根据下面的答案更正了,但是我在第 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);

有什么建议么?

4

2 回答 2

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);
于 2013-02-05T10:37:03.673 回答
1

显示此错误消息是因为您在尝试准备语句时尚未建立与数据库服务器的连接。更短的重现代码:

class Page extends Mysqli{
    public function __construct(){
        $this->prepare('SELECT CURRENT_TIMESTAMP');
    }
}
new Page;

在 mysql 对象中,连接是在构造函数中建立的,但是您覆盖了这样的构造函数并且永远不会调用父构造函数。

恕我直言,页面是数据库对象的实例毫无意义。您应该在需要时简单地提供一个 DB 对象作为参数。

更新:

您可以在每次需要时传递 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){
}

还有其他解决方案,例如接口,但它变得太复杂了:)

于 2013-02-05T10:40:07.077 回答