php - 防止 PHP、PDO 和 MySQL/MariaDB 在不禁用 ATTR_EMULATE_PREPARES 的情况下将整数作为字符串返回

标签 php mysql pdo doctrine-orm doctrine

我有以下架构:

+---------+--------------+------+-----+---------+----------------+
| 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。为什么这很重要?因为这样做显然会破坏。我原来的问题如下,但我知道这实际上并不是一个 Doctrine 问题,而是一个 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 也是 native 类型, https://github.com/php/php-src/blob/php-8.1.0RC1/UPGRADING#L130 所以将来应该可以通过将 PHP 升级到 8.1 来解决这个问题

关于php - 防止 PHP、PDO 和 MySQL/MariaDB 在不禁用 ATTR_EMULATE_PREPARES 的情况下将整数作为字符串返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56853024/

相关文章:

javascript - 单击时可下载文件的超链接,并为每次下载增加一个字段

mysql - 如何修复来自不同组的总和的除法

javascript - 提交表单时将输入文本转换为小写

php - 在 Ubuntu 11 上安装带有 IMAP/Kerberos 支持的 PHP 时出现问题

PHP正则表达式在mysql中检查名称包含重音字母并且名称长度大于5

mysql - 将 MySQL 数据库迁移到 SQLite 时出错

php - 在 PHP 中从 MySQL 结果创建一个没有重复项的数组

php - 准备好的 PDO MySQL 语句提交但更改不坚持

php - PHP PDO 语句可以接受表名或列名作为参数吗?

php - 使用 php 在 mysql 中搜索逗号分隔值