【问题标题】:MySQL integer field is returned as string in PHPMySQL 整数字段在 PHP 中作为字符串返回
【发布时间】:2011-07-16 10:34:12
【问题描述】:

我在 MySQL 数据库中有一个表字段:

userid INT(11)

所以我用这个查询将它调用到我的页面:

"SELECT userid FROM DB WHERE name='john'"

然后处理我做的结果:

$row=$result->fetch_assoc();

$id=$row['userid'];

现在如果我这样做:

echo gettype($id);

我得到一个字符串。这不应该是一个整数吗?

【问题讨论】:

  • MySQL 查询提供行值而不是行类型或任何其他相关信息。只是每个表格单元格中的原始数据。您必须在 PHP 中考虑这一点
  • 如果需要列类型,请看这里forums.whirlpool.net.au/archive/526795
  • 对于读者来说,选择的答案涉及遍历结果。但是有一个更好的解决方案。 stackoverflow.com/a/1197424/5079380
  • @DanHanly - 从技术上讲,MYSQL 查询(在 PHP 中)返回单元格值的 字符串表示 - 存储在数据库中的 32 位整数的实际单元格值是 ... 一个 32 位整数,而不是一串数字。
  • 对我来说,当我使用 $conn->query("your query") 时,我得到了整数字段作为字符串,但是当我使用 $conn->prepare("your query") 时,我得到了数据库中的参数

标签: php mysql types int gettype


【解决方案1】:

当您使用 PHP 从 MySQL 数据库中选择数据时,数据类型将始终转换为字符串。您可以使用以下代码将其转换回整数:

$id = (int) $row['userid'];

或者通过使用函数intval():

$id = intval($row['userid']);

【讨论】:

  • 从 Postgres 背景来到 MySQL,我觉得有必要说这是一个巨大的痛苦。当您在 Postgres 中获取一行时,您可以确保行数组中的元素具有适当的数据类型。现在我不得不编写代码来手动将每个元素转换为我期望的数据类型。
  • 我刚刚在 Windows 上使用 Laravel 和 Mysql 在相同的架构和数据库服务器上进行了一些测试。在 Windows 上,主键作为整数返回,在 Linux 上,它是字符串。
  • 好吧,这是个好主意,但是如果您有数千个字段要检索呢?这个过程需要一段时间。在我的例子中,我检索每个帖子的查看次数,然后我在表格中打印所有帖子,我允许用户按查看 asc 和 desc 排序,但它按“1”到“9”排序" 或 "9" 到 "1" 所以首先你可以有 "9999"、"91"、"8111"、"7" 等等......
  • 返回的每个字段都是一个字符串OR NULL
  • 那么为什么我会得到 int 列的 int 值(我使用的是准备好的语句并在 Windows 上进行了测试)? !
【解决方案2】:

对 php 使用 mysqlnd(本机驱动程序)。

如果您使用的是 Ubuntu:

sudo apt-get install php5-mysqlnd
sudo service apache2 restart

如果你在 Centos 上:

sudo yum install php-mysqlnd
sudo service httpd restart

本机驱动程序适当地返回整数类型。

正如@Jeroen 所指出的,这种方法仅适用于 PDO。
正如@LarsMoelleken 所指出的,如果您还将 MYSQLI_OPT_INT_AND_FLOAT_NATIVE 选项设置为 true,则此方法将适用于 mysqli。

例子:

$mysqli->options(MYSQLI_OPT_INT_AND_FLOAT_NATIVE, TRUE);

【讨论】:

  • 我没有看到任何证据证明这种说法。用mysqlnd和mysqli运行,很明显返回了字符串值。
  • @Jeroen 你确定吗?有很多可用的文档。 stackoverflow.com/questions/1197005/…
  • 是的。另请查看下面的 cmets。你自己测试过这个吗?现在看起来,如果您使用准备好的语句,即使 mysqlnd 也只会返回适当的类型。示例:$link = mysqli_connect('localhost', 'root', ''); mysqli_set_charset($link,'utf8'); $result = mysqli_query($link,'SELECT CAST(\'3.51\' AS DECIMAL(3,2))'); $row = mysqli_fetch_assoc($result); var_dump($row); 返回:array(1) { ["CAST('3.51' AS DECIMAL(3,2))"]=> string(4) "3.51" }
  • 不是我理解的那样,它应该与 PDO 和 Mysqli 一样工作。即使在您在上面的评论中发布的链接上,也明确指出它仅适用于准备好的语句,而不适用于 OP 的内联查询。从该页面引用:但这只是 PHP 5.3(前提是您的 PHP 5.3 版本是用 mysqlnd(而不是旧的 libmysql)编译的),并且似乎只适用于准备好的语句:-(
  • mysqli也可以使用“MYSQLI_OPT_INT_AND_FLOAT_NATIVE”
【解决方案3】:

我找到的最简单的解决方案:

您可以强制 json_encode 对看起来像数字的值使用实际数字:

json_encode($data, JSON_NUMERIC_CHECK) 

(自 PHP 5.3.3 起)。

或者您可以将您的 ID 转换为 int。

$row = $result->fetch_assoc();
$id = (int) $row['userid'];

【讨论】:

  • 如果可能的话,使用json_encode 将字符串转换为 int 就像使用显微镜扼住钉子一样。
  • 这会破坏所有的邮政编码和电话号码。在您的应用程序中引入错误的好方法。解决方案必须尊重 mysql 列数据类型,而不是试图从值中猜测。
  • Max Cuttins,你的观点是正确的。但是,如果您可以考虑到数据库预期的所有数据类型,那么这将是一条完美的路线。
  • 当你有时有类似 '06' 的 id 时,这会伤害你。此标志会将其转换为 6。这是错误的,因为这些 id 应保持尾随零。
  • 例如,对于UNIX_TIMESTAMP() 创建的值,这是一个很好的解决方案。
【解决方案4】:

我的解决方案是传递查询结果$rs,并得到一个转换后的数据的关联数组作为返回:

function cast_query_results($rs) {
    $fields = mysqli_fetch_fields($rs);
    $data = array();
    $types = array();
    foreach($fields as $field) {
        switch($field->type) {
            case 3:
                $types[$field->name] = 'int';
                break;
            case 4:
                $types[$field->name] = 'float';
                break;
            default:
                $types[$field->name] = 'string';
                break;
        }
    }
    while($row=mysqli_fetch_assoc($rs)) array_push($data,$row);
    for($i=0;$i<count($data);$i++) {
        foreach($types as $name => $type) {
            settype($data[$i][$name], $type);
        }
    }
    return $data;
}

示例用法:

$dbconn = mysqli_connect('localhost','user','passwd','tablename');
$rs = mysqli_query($dbconn, "SELECT * FROM Matches");
$matches = cast_query_results($rs);
// $matches is now a assoc array of rows properly casted to ints/floats/strings

【讨论】:

  • 很好的解决方案,除了 'NULL' 也是 settype() 函数使用的变量类型。因此,您的代码将数据库返回的所有 NULL 值(gettype() == 'NULL' 的值)更改为具有 '' 值的 'string' 类型、具有 0 值的 'integer' 类型或具有 0.0 值的 'float' 类型。如果 is_null($data[$i][$name]) 为真,则不需要调用 settype。
  • 我喜欢mastermind的技术,但是coding can be simpler
【解决方案5】:

没有。无论表中定义的数据类型如何,PHP 的 MySQL 驱动程序始终将行值作为字符串提供。

您需要将您的 ID 转换为 int。

$row = $result->fetch_assoc();
$id = (int) $row['userid'];

【讨论】:

  • 不是 PHP 负责(直接)这种行为,它是数据库驱动程序。如果您通过 PHP 与 Postgres 数据库交互,您将获得适当的数据类型。
【解决方案6】:

我喜欢 Chad 的回答,尤其是当查询结果将被传递到浏览器中的 javascript 时。 Javascript 干净地将类似数字的实体作为数字处理,但需要额外的工作才能将类似数字的实体作为字符串处理。即必须对它们使用 parseInt 或 parseFloat。

在 Chad 的解决方案的基础上,我使用它,它通常正是我所需要的,并创建了可以 JSON 编码的结构,以便在 javascript 中轻松处理。

while ($row = $result->fetch_assoc()) {
    // convert numeric looking things to numbers for javascript
    foreach ($row as &$val) {
        if (is_numeric($val))
            $val = $val + 0;
    }
}

将数字字符串添加到 0 会在 PHP 中生成数字类型并正确识别类型,因此浮点数不会被截断为整数。

【讨论】:

    【解决方案7】:

    PDO::ATTR_EMULATE_PREPARES 在连接上设置为true 时会发生这种情况。

    但请注意,将其设置为 false 会禁止多次使用参数。我相信它也会影响返回的错误消息的质量。

    【讨论】:

      【解决方案8】:

      仅适用于 mysqlnd:

       mysqli_options($conn, MYSQLI_OPT_INT_AND_FLOAT_NATIVE, true);
      

      否则:

        $row = $result->fetch_assoc();
      
        while ($field = $result->fetch_field()) {
          switch (true) {
            case (preg_match('#^(float|double|decimal)#', $field->type)):
              $row[$field->name] = (float)$row[$field->name];
              break;
            case (preg_match('#^(bit|(tiny|small|medium|big)?int)#', $field->type)):
              $row[$field->name] = (int)$row[$field->name];
              break;
            default:
              $row[$field->name] = $row[$field->name];
              break;
          }
        }
      

      【讨论】:

        【解决方案9】:

        在我的项目中,我通常使用一个外部函数来“过滤”使用mysql_fetch_assoc 检索到的数据。

        您可以重命名表中的字段,以便直观地了解存储的数据类型。

        例如,您可以为每个数字字段添加特殊后缀: 如果useridINT(11),您可以将其重命名为userid_i,或者如果它是UNSIGNED INT(11),您可以重命名userid_u。 此时,您可以编写一个简单的 PHP 函数,接收关联数组(使用 mysql_fetch_assoc 检索)作为输入,并将转换应用到使用这些特殊“键”存储的“值”。

        【讨论】:

          【解决方案10】:

          在我的情况下,mysqlnd.so 扩展已安装。但我没有pdo_mysqlnd.so。因此,问题已通过将pdo_mysql.so 替换为pdo_mysqlnd.so 解决。

          【讨论】:

            【解决方案11】:
            $mysqli->options(MYSQLI_OPT_INT_AND_FLOAT_NATIVE, TRUE);
            

            试试这个 - 对我有用。

            【讨论】:

            • 程序方法:mysqli_options($conn, MYSQLI_OPT_INT_AND_FLOAT_NATIVE, TRUE);谢谢,真的有效
            【解决方案12】:

            您可以使用...进行此操作

            1. mysql_fetch_field()
            2. mysqli_result::fetch_field_direct
            3. PDOStatement::getColumnMeta()

            ...取决于您要使用的扩展名。不推荐使用第一个,因为不推荐使用 mysql 扩展。第三个仍处于试验阶段。

            这些超链接上的 cmets 很好地解释了如何将您的类型从普通的旧字符串设置为其在数据库中的原始类型。

            一些框架也对此进行了抽象(CodeIgniter 提供了$this-&gt;db-&gt;field_data())。

            您也可以进行猜测——比如遍历结果行并在每个行上使用is_numeric()。类似的东西:

            foreach($result as &$row){
             foreach($row as &$value){
              if(is_numeric($value)){
               $value = (int) $value;
              }       
             }       
            }
            

            这会将任何看起来像数字的东西变成一个...绝对不完美。

            【讨论】:

            • 不适用于浮动。他们通过了 is_numeric 测试。你应该先测试浮点数。
            • @MartinvanDriel 或任何只包含数字但应该是字符串的字符串
            • @MartinvanDriel 尝试添加:if (is_float()) { $value = (float)$value; }
            【解决方案13】:

            如果使用准备好的语句,则类型将在适当的情况下为 int。此代码返回一个行数组,其中每一行都是一个关联数组。就像为所有行调用 fetch_assoc() 一样,但保留了类型信息。

            function dbQuery($sql) {
                global $mysqli;
            
                $stmt = $mysqli->prepare($sql);
                $stmt->execute();
                $stmt->store_result();
            
                $meta = $stmt->result_metadata();
                $params = array();
                $row = array();
            
                while ($field = $meta->fetch_field()) {
                  $params[] = &$row[$field->name];
                }
            
                call_user_func_array(array($stmt, 'bind_result'), $params);
            
                while ($stmt->fetch()) {
                  $tmp = array();
                  foreach ($row as $key => $val) {
                    $tmp[$key] = $val;
                  }
                  $ret[] = $tmp;
                }
            
                $meta->free();
                $stmt->close();
            
                return $ret;
            }
            

            【讨论】:

              【解决方案14】:

              我喜欢mastermind's technique,但编码可以更简单:

              function cast_query_results($result): array
              {
                  if ($result === false)
                    return null;
              
                  $data = array();
                  $fields = $result->fetch_fields();
                  while ($row = $result->fetch_assoc()) {
                    foreach ($fields as $field) {
                      $fieldName = $field->name;
                      $fieldValue = $row[$fieldName];
                      if (!is_null($fieldValue))
                          switch ($field->type) {
                            case 3:
                              $row[$fieldName] = (int)$fieldValue;
                              break;
                            case 4:
                              $row[$fieldName] = (float)$fieldValue;
                              break;
                            // Add other type conversions as desired.
                            // Strings are already strings, so don't need to be touched.
                          }
                    }
                    array_push($data, $row);
                  }
              
                  return $data;
              }
              

              我还添加了对返回 false 而不是结果集的查询的检查。
              并检查具有空值字段的行。
              如果所需的类型是字符串,我不会在上面浪费任何时间 - 它已经是字符串了。


              我不会在大多数 php 代码中使用它;我只是依靠php的自动类型转换。但如果查询大量数据,然后执行算术计算,明智的做法是预先转换为最佳类型。

              【讨论】:

                【解决方案15】:

                MySQL 有许多其他语言的驱动程序,将数据转换为字符串“标准化”数据,并留给用户将值类型转换为 int 或其他

                【讨论】:

                • 我相信原始类型几乎是一个“标准”?如果特定语言的驱动程序无法满足该语言的需求,我会说这非常令人失望
                猜你喜欢
                • 2020-07-19
                • 2014-02-07
                • 2019-12-15
                • 2019-04-25
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2017-01-03
                • 1970-01-01
                相关资源
                最近更新 更多