mysqli :: prepare()和bind_param()的问题

时间:2013-02-05 00:45:42

标签: php sql mysqli

我的申请中有以下课程:

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

有什么建议吗?

2 个答案:

答案 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){
}

还有其他解决方案,比如接口,但它太复杂了。)