php - 防止 PHP、PDO 和 MySQL/MariaDB 在不禁用 ATTR_EMULATE_PREPARES 的情况下将整数作为字符串返回
问题描述
我有以下架构:
+---------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
| someInt | int(11) | NO | | NULL | |
+---------+--------------+------+-----+---------+----------------+
当我运行以下脚本时,整数作为字符串返回。
$pdo = new \PDO("mysql:host={$db['host']};dbname={$db['dbname']};charset={$db['charset']}",$db['username'],$db['password'],array(\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY=>true,\PDO::ATTR_ERRMODE=>\PDO::ERRMODE_EXCEPTION,\PDO::ATTR_DEFAULT_FETCH_MODE=>\PDO::FETCH_ASSOC));
var_dump($pdo->query('SELECT * FROM integerTesting')->fetchAll());
array(3) {
[0]=>
array(3) {
["id"]=>
string(1) "4"
["name"]=>
string(6) "Name 1"
["someInt"]=>
string(1) "1"
}
[1]=>
array(3) {
["id"]=>
string(1) "5"
["name"]=>
string(6) "Name 2"
["someInt"]=>
string(1) "2"
}
[2]=>
array(3) {
["id"]=>
string(1) "6"
["name"]=>
string(6) "Name 3"
["someInt"]=>
string(1) "3"
}
}
因此,我更改PDO::ATTR_EMULATE_PREPARES
为FALSE
,并获得我正在寻找的结果:
$pdo = new \PDO("mysql:host={$db['host']};dbname={$db['dbname']};charset={$db['charset']}",$db['username'],$db['password'],array(\PDO::ATTR_EMULATE_PREPARES=>false,\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY=>true,\PDO::ATTR_ERRMODE=>\PDO::ERRMODE_EXCEPTION,\PDO::ATTR_DEFAULT_FETCH_MODE=>\PDO::FETCH_ASSOC));
var_dump($pdo->query('SELECT * FROM integerTesting')->fetchAll());
array(3) {
[0]=>
array(3) {
["id"]=>
int(4)
["name"]=>
string(6) "Name 1"
["someInt"]=>
int(1)
}
[1]=>
array(3) {
["id"]=>
int(5)
["name"]=>
string(6) "Name 2"
["someInt"]=>
int(2)
}
[2]=>
array(3) {
["id"]=>
int(6)
["name"]=>
string(6) "Name 3"
["someInt"]=>
int(3)
}
}
我回答了我自己的问题吗?不,因为我的问题明确指出没有禁用ATTR_EMULATE_PREPARES
. 为什么这很重要?因为这样做显然会中断。我最初的问题如下,但我知道这不是一个真正的教义问题,而是一个 PDO/MySQL 问题。
我有以下 Doctrine 实体:
<?php
use Doctrine\ORM\Mapping as ORM;
/**
* @Entity @Table(name="integerTesting")
**/
class IntegerTesting
{
/**
* @var int
*
* @Column(type="integer")
* @Id
* @GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/** @Column(type="string") */
protected $name;
/**
* @var int
*
* @Column( type="integer")
*/
protected $someInt;
public function getId()
{
return $this->id;
}
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
return $this;
}
public function getSomeInt()
{
return $this->someInt;
}
public function setSomeInt($someInt)
{
$this->someInt = $someInt;
return $this;
}
}
我添加了一对或记录,然后读取了一些 Doctrine 的 findAll() 方法以及直接 PDO 查询的记录:
<?php
require_once "bootstrap.php";
function addRow(int $i, $entityManager):void {
$e = new IntegerTesting();
$e->setName("Name $i");
$e->setSomeInt($i);
$entityManager->persist($e);
$entityManager->flush();
}
for ($i = 1; $i <= 3; $i++) {
addRow($i, $entityManager);
}
//Using Doctrine's findAll() method
var_dump($entityManager->getRepository('IntegerTesting')->findAll());
//Using direct PDO query
var_dump($entityManager->getConnection()->query('SELECT * FROM integerTesting')->fetchAll());
使用 Doctrine 的 findAll() 方法的输出返回整数列作为所需的整数类型。
array(3) {
[0]=>
object(IntegerTesting)#61 (3) {
["id":protected]=>
int(4)
["name":protected]=>
string(6) "Name 1"
["someInt":protected]=>
int(1)
}
[1]=>
object(IntegerTesting)#63 (3) {
["id":protected]=>
int(5)
["name":protected]=>
string(6) "Name 2"
["someInt":protected]=>
int(2)
}
[2]=>
object(IntegerTesting)#64 (3) {
["id":protected]=>
int(6)
["name":protected]=>
string(6) "Name 3"
["someInt":protected]=>
int(3)
}
}
但是,直接查询将它们作为不需要的字符串返回:
array(3) {
[0]=>
array(3) {
["id"]=>
string(1) "4"
["name"]=>
string(6) "Name 1"
["someInt"]=>
string(1) "1"
}
[1]=>
array(3) {
["id"]=>
string(1) "5"
["name"]=>
string(6) "Name 2"
["someInt"]=>
string(1) "2"
}
[2]=>
array(3) {
["id"]=>
string(1) "6"
["name"]=>
string(6) "Name 3"
["someInt"]=>
string(1) "3"
}
}
我通过设置PDO::ATTR_EMULATE_PREPARES
为找到了一个解决方案FALSE
,但是,经过艰苦的故障排除后,发现它破坏了 Doctrine 的其他一些方面(类类型继承,可能还有其他功能)。
应该如何防止 Doctrine 将整数作为字符串返回?
解决方案
在 php-8.1.0RC1/ 中即使是 EMULATE_PREPARES 也是本机类型, https://github.com/php/php-src/blob/php-8.1.0RC1/UPGRADING#L130 所以将来应该可以通过将 PHP 升级到 8.1
推荐阅读
- mysql - 无法使用部署在 Aws Ecs 上的 .net 核心应用程序连接到 Aurora MySql
- amazon-web-services - AWS Rekognition 集合
- swift - 从 RxSwift 订阅更新菜单
- html - 在 Firefox 上查看列表错误
- java - 如何以编程方式从工作人员处杀死 Beam Dataflow 作业
- zsh - 如何使用连字符启用zsh完成路径
- javascript - 构造输入数组到组件,打字稿中的数据格式(Anuglar/React)
- c# - 会话超时不工作 asp.net mvc
- javascript - 如何在每次重置事件后填写某个值以输入?
- html - 删除下拉菜单旁边的空白