PHP синглтон дизайн PDO - PullRequest
       23

PHP синглтон дизайн PDO

0 голосов
/ 06 октября 2018

Я много лет использую одноэлементный дизайн для PDO на своих сайтах с PHP5.Сейчас я перехожу на PHP7 и вижу ошибки в моем файле журнала apache:

PHP Notice:  Accessing static property Db::$PDOInstances as non static in /var/www/class/class_db_test.php on line 12
PHP Notice:  Accessing static property Db::$PDOInstances as non static in /var/www/class/class_db_test.php on line 13
PHP Notice:  Accessing static property Db::$PDOInstances as non static in /var/www/class/class_db_test.php on line 32

Вот мой класс Singleton для доступа к БД:

<?php
require_once(dirname(__FILE__) . "/../setting.php");

class Db {
    private static $debug = 1;
    private static $debugPath = "/tmp/sql_debug.log";
    private static $PDOInstances = array("db1"=>"","db2"=>"");

    private function __construct($db_type){
        switch($db_type) {
            case "db1":
                $this->PDOInstances[$db_type] = new PDO('mysql:dbname='.DB_NAME.';host='.DB_HOST,DB_USER ,DB_PWD,array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));
                $this->PDOInstances[$db_type]->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
            break;
            case "db2":
                $this->PDOInstances[$db_type] = new PDO('mysql:dbname='.DB2_NAME.';host='.DB2_HOST,DB2_USER ,DB2_PWD,array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));
                $this->PDOInstances[$db_type]->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
            break;
        }
    }
    public static function getInstance($db_type) {
        if(self::$debug == 1){self::sqlDebug("connection","");}

        if(self::$PDOInstances[$db_type] == null){
            self::$PDOInstances[$db_type] = new self($db_type);
        }
        return self::$PDOInstances[$db_type];
    }

    public function query($db_type,$query){
        if(self::$debug == 1){self::sqlDebug("read request",$query);}
        return $this->PDOInstances[$db_type]->query($query);
    }

    public function exec($db_type,$query){
        if(self::$debug == 1){self::sqlDebug("request",$query);}  
        return $this->PDOInstances[$db_type]->exec($query);
    }

    public function lastInsertId($db_type){
        return $this->PDOInstances[$db_type]->lastInsertId();
    }

    public function quote($db_type,$string){
        if(self::$debug == 1){self::sqlDebug("quote",$string);} 
        return $this->PDOInstances[$db_type]->quote($string);
    }

    public static function sqlDebug($_mode,$_query){
        $today = date("m.d.y-H:m:s"); 
        if($_mode == "connection"){
            $line = $today." Connection: '".$_query."'\r\n";
        }
        else if($_mode == "quote"){
            $line = $today." Quote : '".$_query."'\r\n";
        }
        else if($_mode == "request"){
            $line = $today." Request : '".$_query."'\r\n";
        }
        else if($_mode == "read request"){
            $line = $today." Read request : '".$_query."'\r\n";
        }

        $file_debug = fopen(self::$debugPath, "a+");
        fwrite($file_debug, $line);
        fflush($file_debug);
        fclose($file_debug);
    }

}

?>

И мой тестовый код:

<?php
error_reporting(E_ALL); 

require_once(dirname(__FILE__) . "/setting.php");
require_once(dirname(__FILE__) . "/class/class_db_test.php");

$con =  Db::getInstance("db1");
$res = $con->query("db1","SELECT userId from user WHERE userName='test'");

if($res->rowCount() == 1){
    $line = $res->fetchAll();
    $res->closeCursor();
    echo $line[0]['userId'];
}
else{
    echo "0";
}

?>

Когда я заменяю $ this на self :: в строках 12, 13 и 32, я получаю следующие ошибки:

PHP Warning:  Missing argument 2 for Db::query(), called in /var/www/class/class_db_test.php on line 32 and defined in /var/www/class/class_db_test.php on line 30
PHP Notice:  Undefined variable: query in /var/www/class/class_db_test.php on line 31
PHP Notice:  Undefined index: SELECT userId from user WHERE userName='test' in /var/www/class/class_db_test.php on line 32
PHP Fatal error:  Uncaught Error: Call to a member function query() on null in /var/www/class/class_db_test.php:32\nStack trace:\n#0 /var/www/class/class_db_test.php(32): Db->query('SELECT userId f...')\n#1 /var/www/test.php(8): Db->query('db1', 'SELECT userId f...')\n#2 {main}\n  thrown in /var/www/class/class_db_test.php on line 32

У вас есть идеи о том, как адаптировать мой код взаказать заставить его работать на PHP7?

спасибо

Ответы [ 2 ]

0 голосов
/ 06 октября 2018

Учитывая ответ Найджела Рена, вот модифицированный файл класса Db:

<?php
require_once(dirname(__FILE__) . "/../setting.php");

class Db {
    private static $debug = 1;
    private static $debugPath = "/tmp/sql_debug.log";
    private $PDOInstances = "";  // Remove static
    private static $DbInstances = array("db1"=>"","db2"=>"");

    private function __construct($db_type){
        switch($db_type) {
            case "db1":
                $this->PDOInstances = new PDO('mysql:dbname='.DB_NAME.';host='.DB_HOST,DB_USER ,DB_PWD,array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));
                $this->PDOInstances->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
            break;
            case "db2":
                $this->PDOInstances = new PDO('mysql:dbname='.DB2_NAME.';host='.DB2_HOST,DB2_USER ,DB2_PWD,array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));
                $this->PDOInstances->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
            break;
        }
    }
    public static function getInstance($db_type) {
        if(self::$debug == 1){self::sqlDebug("connection","");}

        if(self::$DbInstances[$db_type] == null){
            self::$DbInstances[$db_type] = new self($db_type);
        }
        return self::$DbInstances[$db_type];
    }

    public function query($query){
        if(self::$debug == 1){self::sqlDebug("read request",$query);}
        return $this->PDOInstances->query($query);
    }

    public function exec($query){
        if(self::$debug == 1){self::sqlDebug("request",$query);}  
        return $this->PDOInstances->exec($query);
    }

    public function lastInsertId(){
        return $this->PDOInstances->lastInsertId();
    }

    public function quote($string){
        if(self::$debug == 1){self::sqlDebug("quote",$string);} 
        return $this->PDOInstances->quote($string);
    }

    public static function sqlDebug($_mode,$_query){
        $today = date("m.d.y-H:m:s"); 
        if($_mode == "connection"){
            $line = $today." Connection: '".$_query."'\r\n";
        }
        else if($_mode == "quote"){
            $line = $today." Quote : '".$_query."'\r\n";
        }
        else if($_mode == "request"){
            $line = $today." Request : '".$_query."'\r\n";
        }
        else if($_mode == "read request"){
            $line = $today." Read request : '".$_query."'\r\n";
        }

        $file_debug = fopen(self::$debugPath, "a+");
        fwrite($file_debug, $line);
        fflush($file_debug);
        fclose($file_debug);
    }

}

?>

И тестовый файл:

<?php
error_reporting(E_ALL); 

require_once(dirname(__FILE__) . "/setting.php");
require_once(dirname(__FILE__) . "/class/class_db_test.php");

$con =  Db::getInstance("db1");
$res = $con->query("SELECT userId from user WHERE userName='test'");

if($res->rowCount() == 1){
    $line = $res->fetchAll();
    $res->closeCursor();
    echo $line[0]['userId'];
}
else{
    echo "0";
}

?>

Все работает без PHP Notice / Error.

Спасибо!

0 голосов
/ 06 октября 2018

Одна из основных вещей, которые я вижу, это то, что вы используете PDOInstances двумя разными способами.Он используется для списка экземпляров вашего класса Db (устанавливается в статическом методе getInstance()).НО также кажется, что вы пытаетесь сохранить экземпляр PDO для базы данных (в конструкторе).

Если вы изменяете переменную, которую используете для хранения базы данных (класс Db),тогда это будет, по крайней мере, означать, что у вас есть обе части данных ...

private $PDOInstances = array("db1"=>"","db2"=>"");  // Remove static
private static $DbInstances = array("db1"=>"","db2"=>"");


public static function getInstance($db_type) {
    if(self::$debug == 1){self::sqlDebug("connection","");}

    if(self::$DbInstances[$db_type] == null){
        self::$DbInstances[$db_type] = new self($db_type);
    }
    return self::$DbInstances[$db_type];
}

Я также не уверен, почему, когда вы звоните

$con =  Db::getInstance("db1");

, вам нужно передать БДвведите для всех других методов ...

$res = $con->query("db1","SELECT userId from user WHERE userName='test'");

Конечно, это должно подразумеваться из-за соединения, вызываемого с типом базы данных.

Если в конструкторе вы только что это сделали (установитеPDOInstances без части массива)

$this->PDOInstances = new PDO('mysql:dbname='.DB_NAME.';host='.DB_HOST,DB_USER ,DB_PWD,array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));

, тогда весь доступ к базе данных осуществляется через этот ...

public function query($query){
    if(self::$debug == 1){self::sqlDebug("read request",$query);}
    return $this->PDOInstances->query($query);
}
...