【问题标题】:PHP Singleton design PDOPHP Singleton 设计 PDO
【发布时间】:2019-03-11 15:28:53
【问题描述】:

多年来,我一直在我的网站上使用 PHP5 为 PDO 使用单例设计。 我现在正在迁移到 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

这是我的用于 DB 访问的 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";
}

?>

当我在第 12、13 和 32 行将 $this 更改为 self:: 时,出现这些错误:

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 有什么想法吗?

谢谢

【问题讨论】:

    标签: php pdo singleton php-7


    【解决方案1】:

    我可以看到的主要内容之一是您以两种不同的方式使用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");
    

    然后您需要将 db 类型传递给所有其他方法...

    $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);
    }
    

    【讨论】:

      【解决方案2】:

      考虑到 Nigel Ren 的回答,这里是修改的 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 通知/错误。

      谢谢!

      【讨论】:

        猜你喜欢
        • 2016-09-05
        • 1970-01-01
        • 2017-01-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-17
        • 2019-05-09
        • 2011-10-27
        相关资源
        最近更新 更多