PHP、PDO和遗留DB-动态更改字符集



我使用PHP已经很久了。需要将非常非常旧的站点从mysql_*升级到PDO。迁移工作得很好,但DB是一个由Latin1utf8混合表组成的可怕的烂摊子。无法改变这一点。

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

在旧代码中,使用mysql_set_charset()"解决"了这个问题,但不幸的是,我找不到PDO等效。

如何在PDO连接上动态更改字符集?这可能吗?或者有人能提出一种模式吗?

这是由从PHP5.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');

当使用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。

已经有了一个公认的答案,但我将发布这个答案只是为了将我在注释中的想法扩展到您的示例代码中。

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

最新更新