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

时间:2019-07-02 12:56:46

标签: 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。为什么这么重要?因为这样做显然会中断。我的原始问题在下面,但是我知道这不是一个真正的教义问题,而是一个PDO / MySQL问题。

我有以下学说实体:

<?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将整数作为字符串返回?

1 个答案:

答案 0 :(得分:0)

好吧,我在禁用cell (td)时,猜测它在技术上无法回答问题。但是,它对我有用,因为我可以在每个查询的基础上这样做,因此不会令教义不安。

\PDO::ATTR_EMULATE_PREPARES