PHP、PDO 和遗留数据库 - 即时更改字符集?

PHP, PDO and legacy DB - change charset on the fly?

好久没用了PHP。需要将一个非常非常旧的站点从 mysql_* 升级到 PDO。迁移工作正常,但数据库是混合 Latin1utf8 表的可怕混乱。无法改变这一点。

看到了一个巧妙的解决方案 here,您只需为每种类型的字符集创建一个连接,但我的问题是该站点是作为 classes 的层次结构构建的,所有这些都来自单个 Db class,它在初始化时定义字符集。

在旧代码中,问题是 "solved" 通过使用 mysql_set_charset(),但不幸的是我找不到 PDO 等价物。

如何在 PDO 连接上即时更改字符集?有可能吗? 或者谁能​​推荐一种模式?

这是 "fever rescue" 由 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 [
  ...
}

想在Dbclass上实现一个方法所以我在继承classes上可以执行例如$this->changeCharset('Latin1');

当使用PDO连接到MySQL时,明确设置字符集为utf8是明智的(当然,只有在使用utf8时才是字符集)。在 MySQL 或 MySQLi 扩展中,我通常会执行查询 SET NAMES utf8 来设置它。

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

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

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

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

但是你不应该 运行宁这样一个旧版本的 PHP 无论如何。

已经有一个可接受的答案,但我 post 这只是为了将我在评论中的想法扩展到您的示例代码中。

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