2016-08-30 3 views
0

Случай, когда я получаю эту ошибку, отличается от того, что я видел на SO, пытаясь решить мою проблему. У меня есть класс Database, который создает только один экземпляр сам по себе, пытаясь ограничить количество соединений с сервером mysql одним. Вот мой класс [код 1]:Закрытие PHP mysqli с ошибкой базы данных

class Database { 

    private $_connection; 

    // Store the single instance. 
    private static $_instance; 

    /** 
    * Get self instance of database to private static variable $_instance. 
    * @param string $host 
    * @param string $username 
    * @param string $password 
    * @param string $database 
    * @return Database 
    */ 
     public static function getInstance($host,$username,$password,$database) { 
      if (!self::$_instance) { 
       self::$_instance = new self($host,$username,$password,$database); 
      } 
      return self::$_instance; 
     } 

     /** 
     * Constructor. 
     * @param string $host 
     * @param string $username 
     * @param string $password 
     * @param string $database 
     */ 
     public function __construct($host,$username,$password,$database) { 
      $this->_connection = new mysqli($host, $username, $password, $database); 

     // Error handling. 
     if (mysqli_connect_error()) { 
      trigger_error('Failed to connect to MySQL: ' . mysqli_connect_error(), E_USER_ERROR); 
     } 
    } 

    /** 
    * Empty clone magic method to prevent duplication. 
    */ 
    private function __clone() {} 

    /** 
    * Get the mysqli connection; 
    */ 
     public function getConnection(){ 
      return $this->_connection; 
     } 
    } 

После этого класса, я создал соединение для получения некоторой информации из таблицы. Код следующий [код 2]:

// Establish a connection with MySQL Server database. 
    $host = 'localhost'; 
    $username = 'barbu'; 
    $password = 'watcrn0y'; 
    $database = 'siteinfo'; 

    $db = Database::getInstance($host, $username, $password, $database); 
    $mysqli = $db->getConnection(); 

    // Get the firstname of the author of the site from database. 
    $sql_query = 'SELECT author.firstname, author.lastname '; 
    $sql_query .= 'FROM author;'; 

    $result = $mysqli->query($sql_query); 


    if($result && $row = $result->fetch_assoc()){ 
     $author_firstname = $row['firstname']; 
     $author_lastname = $row['lastname']; 
    } 

Теперь, в другом файле, я делаю это [код 3]:

require '../includes/siteinfo.php'; // this file contains the connection 
    // with first database ['siteinfo']. 
    //I include this file for accessing some other variables from it, which aren't 
    //in the code posted above. 

// Establish the connection to server. 
$host = 'localhost'; 
$username = 'barbu'; 
$password = 'watcrn0y'; 
$database = 'articles'; 

// Here I need to close my previous connection and begin another. 
// It is important to remember that my class is designed for creating 
// just one connection at a time. 
// So if I want to change the connection to another database, 
// I have to close the previous one and create the one which 
// suits my needs. 
$mysqli->close(); 
unset($db); 

$db = Database::getInstance($host, $username, $password, $database); 
$mysqli = $db->getConnection(); 



// Send the post info to the server. 
$title = (isset($_POST['title'])) ? $_POST['title'] : ''; 
$text = (isset($_POST['text'])) ? $_POST['text'] : ''; 
$sql = "INSERT INTO postInfo "; 
$sql .= "VALUES ('" . $author_firstname . " " . $author_lastname ."', '" . 
date('d D M Y') . "', '" . $title . "', '" . $text . "');"; 
$result = $mysqli->query($sql); 

При этом, я получаю ошибку :

Warning: mysqli::query(): Couldn't fetch mysqli in /home/barbu/blog/admin/index.php on line 24

Если я не закрываю первое соединение (и пусть говорят, я позволяю только [ «снята с охраны ($ дб)»]), мой запрос будет выполнен на пихты st database ['siteinfo'], и я получаю еще одно сообщение об ошибке, а именно сообщение о том, что таблица «postInfo» не существует в базе данных «siteinfo», что верно. Если я разрешаю этому соединению продолжать и объявляет еще один экземпляр класса базы данных, $ db1 и другого объекта mysqli, $ mysqli1, которые поддерживают мое соединение и выполняют мой запрос через него, я получаю то же сообщение об ошибке mysqli, как и во втором случае : 'siteinfo.postInfo' не существует. Что вы мне посоветовали? Как я могу решить эту проблему?

+0

** ПРЕДУПРЕЖДЕНИЕ ** При использовании 'mysqli' вы должны использовать [параметризованные запросы] (HTTP://php.net/manual/en/mysqli.quickstart.prepared-statements.php) и ['bind_param'] (http://php.net/manual/en/mysqli-stmt.bind-param.php), чтобы добавить пользовательские данные в ваш запрос. ** НЕ используйте ** интерполирование строк или конкатенацию для выполнения этого, потому что вы создали серьезную [SQL-инъекцию] (http://bobby-tables.com/). ** НИКОГДА не ставьте данные '$ _POST' или' $ _GET' непосредственно в запрос, это может быть очень вредно, если кто-то пытается использовать вашу ошибку. – tadman

+0

Есть ли причина, по которой вы пишете свою собственную ОРМ, когда есть несколько первоклассных? Использование [Doctrine] (http://www.doctrine-project.org/) или [Propel] (http://propelorm.org/) настоятельно рекомендуется перед тем, как вы выкопаете себе слишком глубокую дыру. – tadman

+0

@tadman: Я не слышал об этих двух библиотеках. Я даже не знал, что означает ORM. Я посмотрю на этих двух и попробую ознакомиться с ними. Я думаю, что мне будет легче справляться в начальных базах данных. Спасибо за ваш ответ! –

ответ

0

Прежде всего, если вы хотите иметь только одно соединение за сеанс и не разрешать создание экземпляра seccond, вы должны указать Database::__construct как закрытый. Затем добавьте новый метод Database::close. Идея этого метода заключается в том, чтобы закрыть соединение и установить ссылку на экземпляр класса Database на null. Код будет выглядеть следующим образом:

public function close() 
{ 
    if (self::$_instance) { 
     self::$_instance->getConnection()->close(); 
     self::$_instance = null; 
    } 
} 

Окончательной точка, вместо $mysqli->close(); вы должны вызвать $db->close();

+0

Ну, вот ответ! Большое вам спасибо, все работает отлично! Кроме того, почему я должен определять, как Database :: __ построить private, чтобы получить это поведение для моего класса? Я не совсем понял это. –

+0

Потому что возможно создать новый экземпляр типа $ db = new Database(); и вы хотите избежать этого. @lulian –

+0

О, я вижу. Когда вы создаете новый экземпляр объекта, вызывается метод построения метода, поэтому определение его как private не позволяет методу выполнить. –

Смежные вопросы