PDOStatement:在 `fetchAll($mode);` 和 `setFetchMode($mode); 之间得到不同的结果;获取所有();`

2022-01-20 00:00:00 arrays fetch php pdo

我有一个关于 PDO 的问题.

I have a question regarding PDO.

有没有区别

$sql = "SELECT * FROM pages";
$pdo = $this->db->query($sql);
$result = $pdo->fetchAll(PDO::FETCH_GROUP|PDO::FETCH_ASSOC); 

$sql = "SELECT * FROM pages";
$pdo = $this->db->query($sql);
$pdo->setFetchMode(PDO::FETCH_GROUP|PDO::FETCH_ASSOC);
$result = $pdo->fetchAll();

?

我为每个人得到一个不同的 $result.

I get a different $result for each of them.

PHP 关于这些获取模式的文档对我来说不是很清楚.

The documentation from PHP about these fetch modes is not very clear to me.

我有一个包含不同页面的表,我想获取所有按其 ID 索引的页面.

I have a table with different pages, and I want to fetch all the pages indexed by their ID.

第一个方法返回这个:

[
   [id of page 1] => [
      [0] => [ page 1 ],
   ],
   [id of page 2] => [
      [0] => [ page 2 ],
   ],
   ...
]

当我做第二种方法时,我只得到:

When I do the second method, I only get:

[
   [0] => [ page 1 ],
   [1] => [ page 2 ],
   [3] => [ page 3 ],
   ...
]

我想要这样:

[
   [id of page 1] => [ page 1 ],
   [id of page 2] => [ page 2 ],
   [id of page 3] => [ page 3 ],
   ...
]

第一个对我来说已经足够了,因为我可以使用数组映射函数轻松调整它:

The first one is good enough for me because I can easily tweak it with the array map function:

array_map('reset', $result);

推荐答案

解释好像是 fetchAll()setFetchMode() 支持不同的集合 PDO::FETCH__ 常量.

The explanation seems to be that fetchAll() and setFetchMode() support different sets of PDO::FETCH__ constants.

我认为 setFetchMode() 会忽略 PDO::FETCH_GROUP,但不会忽略 PDO::FETCH_ASSOC.

I think setFetchMode() ignores PDO::FETCH_GROUP, but not PDO::FETCH_ASSOC.

我从 PHP 源代码中确认了这一点,请参阅 setFetchMode() 实现.setFetchMode 支持的常量列表不包括 PDO::FETCH_GROUP.

I confirmed this from the PHP source code, see the setFetchMode() implementation. The list of constants supported by setFetchMode does not include PDO::FETCH_GROUP.

<?php

$db = new PDO('mysql:host=localhost;dbname=test', 'root');

// print the default output, no constants
$sql = "SELECT * FROM service_table";
$q = $db->query($sql);
$result = $q->fetchAll();
echo 'Result 0' . PHP_EOL;
var_dump($result);

// use fetchAll() with constants
$sql = "SELECT * FROM service_table";
$q = $db->query($sql);
$result = $q->fetchAll(PDO::FETCH_GROUP | PDO::FETCH_ASSOC);
echo 'Result 1' . PHP_EOL;
var_dump($result);

// use setFetchMode with constants
$sql = "SELECT * FROM service_table";
$q = $db->query($sql);
$q->setFetchMode(PDO::FETCH_GROUP | PDO::FETCH_ASSOC);
$result = $q->fetchAll();
echo 'Result 2' . PHP_EOL;
var_dump($result);

测试数据

mysql> select * from test.service_table;
+----+------+
| id | name |
+----+------+
|  1 | one  |
|  2 | two  |
+----+------+

结果 0

这是默认设置,结果不分组,并且有基于名称和基于索引的字段:

Result 0

This is the default, results are not grouped and there are both name-based and index-based fields:

array(2) {
  [0] =>
  array(4) {
    'id' => string(1) "1"
    [0] => string(1) "1"
    'name' => string(3) "one"
    [1] => string(3) "one"
  }
  [1] =>
  array(4) {
    'id' => string(1) "2"
    [0] => string(1) "2"
    'name' => string(3) "two"
    [1] => string(3) "two"
  }
}

结果 1

这是 $q->fetchAll(PDO::FETCH_GROUP | PDO::FETCH_ASSOC) 的结果.我们有 FETCH_GROUPFETCH_ASSOC 的效果:

Result 1

This is the result of $q->fetchAll(PDO::FETCH_GROUP | PDO::FETCH_ASSOC). We have the effects of both FETCH_GROUP and FETCH_ASSOC:

array(2) {
  [1] => array(1) {
    [0] => array(1) {
      'name' => string(3) "one"
    }
  }
  [2] => array(1) {
    [0] => array(1) {
      'name' => string(3) "two"
    }
  }
}

结果 2

这是$q->setFetchMode(PDO::FETCH_GROUP | PDO::FETCH_ASSOC);的结果,我们只有FETCH_ASSOC的效果:

Result 2

This is the result of $q->setFetchMode(PDO::FETCH_GROUP | PDO::FETCH_ASSOC);, we have only the effect of FETCH_ASSOC:

array(2) {
  [0] => array(2) {
    'id' => string(1) "1"
    'name' => string(3) "one"
  }
  [1] => array(2) {
    'id' => string(1) "2"
    'name' => string(3) "two"
  }
}

这样,FETCH_GROUP 适用于 fetchAll(),但不适用于 setFetchMode().FETCH_ASSOC 在这两种情况下都有效.

This way, FETCH_GROUP works for fetchAll(), but doesn't work for setFetchMode(). FETCH_ASSOC works in both cases.

现在,来自文档的间接确认:

Now, an indirect confirmation from docs:

这里是所有PDO 常量的列表.PDO::FETCH_FUNC 的描述说:

Here is the list of all PDO constants. The description for PDO::FETCH_FUNC says:

允许完全自定义动态处理数据的方式(仅在 PDOStatement::fetchAll() 内部有效).

Allows completely customize the way data is treated on the fly (only valid inside PDOStatement::fetchAll()).

所以我们知道至少这个常量只适用于fetchAll(),并且可以假设其他常量可能并不适用于任何地方.

So we know that at least this constant only works for fetchAll(), and can assume that other constants may work not everywhere.

另外,如果我们查看 fetch(),我们在那里看到有限的常量列表.

Also if we look at the docs for fetch(), we see a limited list of constants there.

例如 PDO::FETCH_GROUPPDO::FETCH_UNIQUE 存在于 fetchAll() 描述,但不存在于 fetch() 描述中.

For example PDO::FETCH_GROUP and PDO::FETCH_UNIQUE are present in the fetchAll() description, but are not present in the fetch() description.

所以我认为与多行操作相关的常量,例如 PDO::FETCH_GROUP,仅用于 fetchAll() 并被 fetch()setFetchMode().

So I think constants related to multi-row operations, such as PDO::FETCH_GROUP, are only used for fetchAll() and ignored by fetch() and setFetchMode().

我尝试了几个组合,看起来 FETCH_GROUP + FETCH_UNIQUE 可以.

I tried few combinations and it looks like FETCH_GROUP + FETCH_UNIQUE does it.

$sql = "SELECT * FROM service_table";
$q = $db->query($sql);
$result = $q->fetchAll(PDO::FETCH_GROUP | PDO::FETCH_UNIQUE | PDO::FETCH_ASSOC);
var_dump($result);

结果

array(2) {
  [1] => array(1) {
    'name' => string(3) "one"
  }
  [2] => array(1) {
    'name' => string(3) "two"
  }
}

另一种选择是使用带有自定义函数的 FETCH_FUNC 来格式化数据,请参阅 fetchAll() 文档.

Another option can be to use FETCH_FUNC with custom function to format data, see the fetchAll() docs.

相关文章