PHP,PDO和旧版数据库-动态更改字符集?

时间:2018-11-30 06:00:08

标签: php pdo php-7.2

自从我使用PHP以来已经很长时间了。需要将非常老的站点从mysql_*升级到PDO。迁移工作得很好,但是数据库混杂了Latin1utf8表,这真是一团糟。无法更改。

见过一个整洁的解决方案here,您只需要为每种字符集创建一个连接,但是我的问题是,该站点是作为类的层次结构构建的,这些类都源自单个Db类,该类定义了初始化时的字符集。

在旧代码中,问题是通过使用mysql_set_charset()“解决”的,但不幸的是,我找不到PDO等效项。

如何在PDO连接上即时更改字符集?可能吗  还是有人可以建议一种模式?

这是从PHP 5.x升级到7.2引起的“狂热拯救”,它不是重构整个代码库或数据库的选项。


它或多或少是这样的:

class Db {
  private $pdo;

  public function __construct() {  
    $dsn = "mysql:host=".$this->hostname.";dbname=".$this->database.";charset=".$this->charset;

    $opt = [
      PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
      PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
      PDO::ATTR_EMULATE_PREPARES   => false
    ];

    try {
      $this->pdo = new PDO($dsn, $this->username, $this->password, $opt);
    } catch(PDOException $e) {
      echo "Error connecting to database: ". $e->getMessage();
    }
  }
}

class AnotherClass extends Db {
  public function __construct() {  
    parent::__construct();
    ...
  }
}

class YetAnotherClass extends AnotherClass [
  ...
}

想在Db类上实现一个方法,以便我在继承的类中可以执行例如$this->changeCharset('Latin1');

2 个答案:

答案 0 :(得分:1)

使用PDO连接到MySQL时,明智的做法是将字符集显式设置为utf8(当然,仅当使用utf8时才是字符集)。在MySQL或MySQLi扩展中,我通常会执行查询SET NAMES utf8进行设置。

在PDO中,可以在连接字符串中指定字符集:

$conn = new PDO("mysql:host=$host;dbname=$db;charset=utf8", $user, $pass);

charset选项仅自PHP 5.3.6起使用,因此在运行旧版本的PHP时要考虑到这一点。在这种情况下,您应该在构造PDO对象之后运行以下语句:

$conn->exec('SET NAMES utf8');

但是无论如何,您都不应运行这样的旧版本的PHP。

答案 1 :(得分:1)

已经有一个可以接受的答案,但是我将其发布只是为了将我的想法扩展到您的示例代码中。

class Db {
  private $pdo;

  public function __construct($charset) {  
   $dsn = "mysql:host=".$this->hostname.";dbname=".$this->database.";charset=".$charset;

   $opt = [
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES   => false
   ];

   try {
    $this->pdo = new PDO($dsn, $this->username, $this->password, $opt);
   } catch(PDOException $e) {
     echo "Error connecting to database: ". $e->getMessage();
   }
  }
}

class AnotherClass extends Db {
  public function __construct() {  
    parent::__construct('latin1');
  }
}