Дизайн класса базы данных - PullRequest
1 голос
/ 04 марта 2012

Я создаю веб-приложение с различными классами для таких вещей, как пользователь, элемент управления Smarty и т. Д.

У меня уже есть класс базы данных, и все хорошо, но я беспокоюсь о его производительности.

В настоящее время в другом классе я делаю $this->db = new DB() для создания экземпляра локальной базы данных, однако функция __construct() класса базы данных создает новое соединение с сервером MySQL каждый раз, когда я создаю новый экземпляр DB(), что явно менее чем разумно. Это означает, что каждый экземпляр всех моих разных классов, использующий класс базы данных, устанавливает соединение с сервером. У меня нет большого количества классов, но я хочу только один для каждой загрузки страницы.

Это урезанный образец того, что у меня есть на данный момент:

// Database class used by multiple other classes
class DB {
    private $dbh;

    function __construct() {
        $this->dbh = // PDO connection here
    }

    public function query($str) {
        // Do a query
    }
}

// Example class User
class User {
    private $db;    // Stores local instance of DB class.

    function __construct() {
        $this->db = new DB();    // Makes a new connection in DB::__construct()
    }

    public function login() {
        $this->db->query('SELECT * FROM users');
    }
}

Я ищу "лучшую" или наиболее распространенную практику для этого. Я не хочу делать 10 отдельных подключений для каждой загрузки страницы.

Я хочу знать, как лучше всего использовать класс БД в моем приложении и управлять им. Вот мои четыре мысли:

  1. Будет ли использование постоянного подключения к серверу MySQL решить эту проблему с несколькими подключениями для меня?
  2. Должен ли я использовать статический фабричный класс и возвращать экземпляр БД вместо использования new DB()?
  3. Правильное ли решение использовать полностью статический класс и просто делать DB::query() (например) каждый раз, когда я ссылаюсь на него?
  4. Я часто использую несколько классов в другом (поэтому у нас может быть класс Folders, который требует классов User, DB и Smarty). Является ли это общей практикой для extend каждого класса как-нибудь?

Ответы [ 4 ]

2 голосов
/ 04 марта 2012

Если вы сделаете переменную, содержащую соединение, статической, то вы можете проверить, установили ли вы соединение. Статические переменные одинаковы для всех экземпляров класса, поэтому вы можете создать 100 экземпляров, которые используют одно и то же соединение. Вам просто нужно ссылаться на него статически: self :: $ dbh вместо $ this-> dbh.

class DB {
    private static $dbh = null;

    function __construct() {
        if ( is_null(self::$dbh) ) {
            self::$dbh = // PDO connection here
        }
    }
 }
1 голос
/ 04 марта 2012

Я бы посоветовал вам сначала проверить $ this -> db, а затем только создать его.

function __construct() {
        if(!isset($this -> db) || !is_a("DB", $this -> db)) {
         $this->db = new DB();    // Makes a new connection in DB::__construct()
    }
}
0 голосов
/ 18 апреля 2015
<?php

class DBLayer {

    public $prefix;
    public $link_id;
    public $query_result;
    public $saved_queries = array();
    public $num_queries = 0;

    public function DBLayer() {

        $db_prefix = '';
        $this->prefix = $db_prefix;
        if (isset($this->link_id)) {
            return $this->link_id;
        }
        $this->link_id = @mysql_connect(DATABASE_HOST, DATABASE_USER, DATABASE_PASSWORD, true);

        if ($this->link_id) {
            if (@mysql_select_db(DATABASE_NAME, $this->link_id)) {
                return $this->link_id;
            } else {
                $this->wplog("Unable to select database. Host:". DATABASE_HOST. "Database:" . DATABASE_NAME   . " Error: " . mysql_error(), 'ERROR', __FILE__, __LINE__);
            }
        } else {
            $this->wplog("Unable to connect to MySQL server. Host: " . DATABASE_HOST . " Error: " . mysql_error(), 'ERROR', __FILE__, __LINE__);
        }
    }

    public function query($sql, $unbuffered = false) {

        if(LOG){echo "<hr>$sql";}

        $this->query_result = @mysql_query($sql, $this->link_id);

        if ($this->query_result) {
            return $this->query_result;
        } else {
            $msg= $sql . "<br /> Error: (" . mysql_errno() . ") " . mysql_error();
            $this->wplog($msg);
        }
    }

    public function result($query_id = 0, $row = 0) {
        return ($query_id) ? @mysql_result($query_id, $row) : false;
    }

    public function fetch_assoc($query_id = 0) {
        return ($query_id) ? @mysql_fetch_assoc($query_id) : false;
    }

    public function fetch_row($query_id = 0) {
        return ($query_id) ? @mysql_fetch_row($query_id) : false;
    }

    public function num_rows($query_id = 0) {
        return ($query_id) ? @mysql_num_rows($query_id) : false;
    }

    public function affected_rows() {
        return ($this->link_id) ? @mysql_affected_rows($this->link_id) : false;
    }

    public function insert_id() {
        return ($this->link_id) ? @mysql_insert_id($this->link_id) : false;
    }

    public function get_num_queries() {
        return $this->num_queries;
    }

    public function get_saved_queries() {
        return $this->saved_queries;
    }

    public function free_result($query_id = false) {
        return ($query_id) ? @mysql_free_result($query_id) : false;
    }

    public function escape($str) {
        if (function_exists('mysql_real_escape_string'))
        return mysql_real_escape_string($str, $this->link_id);
        else
        return mysql_escape_string($str);
    }

    public function get_select($q, $onlyone=false) {

        $results = array();

        $r = $this->query($q);

        if ($onlyone) {
            return $this->fetch_assoc($r);
        }
        while ($l = $this->fetch_assoc($r)) {

            $results[] = $l;
        }

        return $results;
    }

    public function get_error() {
        return mysql_error();
    }

    public function close() {
        if ($this->link_id) {
            if ($this->query_result)
            @mysql_free_result($this->query_result);

            return @mysql_close($this->link_id);
        }
        else
        return false;
    }

    public function auto_execute($table, $data, $type, $criteria='') {

        $result = $this->get_select("desc " . $table);


        if ($type == "INSERT")
        $start = "insert into " . $table . " set ";
        elseif ($type == "UPDATE")
        $start = "update " . $table . " set ";
        $sql = $start;
        foreach ($result as $rst) {
            foreach ($data as $key => $value) {
                if ($key == $rst['Field'] and $key !== 0) {
                    if ((@ereg('date', $rst['Type'])) && $value == '') {
                        $sql = $sql . "`".$key."`" . "=NULL, ";
                    } elseif ((!@ereg('int', $rst['Type']))) {
                        $sql = $sql . "`".$key."`" . "='" . $value . "', ";
                    } else {
                        if (trim($value) != "") {
                            $sql = $sql . "`".$key."`" . "=" . $value . ", ";
                        }
                    }
                }
            }
        }

        if ($sql == $start)
        return 0;
        else {
            $sql = substr($sql, 0, strlen($sql) - 2);
            if ($type == "UPDATE" and !empty($criteria))
            $sql = $sql . " where " . $criteria;
        }
        //echo $sql;exit;
        if ($this->query($sql)) {
            $return = $this->insert_id();
        } else {
            $return = 0;
        }
        return $return;
    }
    private function wplog($message) {
        if(LOG==true){
            $lineBreak = "\n"; // this function will NOT work on a windows server without further modification

            $contents = date('Y-m-d H:i:s') . ' ' . $message. $lineBreak;

            $myFile = SERVER_PATH.'/log.txt';
$fh = fopen($myFile, 'a') ;
fwrite($fh, $contents);
fclose($fh);

            //SetFileContents(SERVER_PATH.'/log.txt',$contents,'a');
        }
    }

}
0 голосов
/ 04 марта 2012

Вам нужно внедрить соединение БД в ваш класс вместо создания нового соединения.

// In a bootstrap file
$db = new DB(); 


// User.php
class User {
    private $db;

    function __construct($db=null) {
       if (!is_null($db)) {
          $this->setConnection($db);
       }
    }

    function setConnection($db) {
       $this->db = $db;
    }

    public function login() {
        $this->db->query('SELECT * FROM users');
    }
}

Кстати, Zend_Registry - хорошее решение, если вы предпочитаете это http://framework.zend.com/manual/en/zend.registry.using.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...