You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

升级PHP、Yii、MariaDB后institutionId类型变更的原因及全局修复方法

技术栈升级后API字段类型变更问题分析与修复

版本变更详情

ComponentOld VersionNew Version
PHP7.3.08.3.0
Yii2.0.62.0.51
MariaDB10.1.3411.6.2

API响应变化

旧版本响应(institutionId为字符串类型)

{
"statusCode": 200,
"message": "",
"data": {
"institutionId": "66"
} }

新版本响应(institutionId为整数类型)

{
"statusCode": 200,
"message": "",
"data": {
"institutionId": 66
} }

相关代码片段

API控制器方法

public function actionGetInstitutionDetails()
{
    $request = Yii::$app->request;
    $user = $request->get('userId');
    $institutionId = $request->get('institutionId');
    $userId =  $user ? $user : yii::$app->user->identity->id;   
    if ($userId && $institutionId) {
            
            $institutionDetails = ExtendedInstitution::getInstitutionData($institutionId);
            $resultSet = [];
            $result = new \stdClass();
            if ($institutionDetails) {
                foreach ($institutionDetails as $key => $value) {
                    $data = new \stdClass();
                    $data->institutionId = (!empty($value['id'])) ? $value['id'] : '';
                    $data->institutionName = (!empty($value['name'])) ? $value['name'] : '';
                    $data->phoneNumber2 = (!empty($value['phone2'])) ? $value['phone2'] : 'Not available';
                    $data->email = (!empty($value['email'])) ? $value['email'] : '';
                    $data->website = (!empty($value['url'])) ? $value['url'] : '';
                }
            $this->statusCode = 200;
            $this->message = '';
            $this->data = $data;
            return new ApiResponse($this->statusCode, $this->data,$this->message);  
            }
        }
    } 

数据获取方法与存储过程

public static function getInstitutionData($institutionId)
{
    try {
        $institutionDetails = Yii::$app->db->createCommand(
                "CALL get_institution(:institutionid)")
                ->bindValue(':institutionid' , $institutionId )
                ->queryAll();
        return $institutionDetails;
        
    } catch (Exception $e) {
        return false;
    }
}
CREATE DEFINER=`root`@`%` PROCEDURE `get_institution`(institutionid int)
BEGIN
SELECT 
    i.id,
    i.`name`,
    i.pin,
    i.institutionlogo,
    i.email,
    i.url,
    i.moreurl,
    i.institutiontype AS 'institutiontypeid',
FROM
    institution i
WHERE
    i.id = institutionid;
END

API响应类

class ApiResponse implements \JsonSerializable
{
    public $statusCode;
    public $data;
    public $message = "";
    
    public function __construct($status = null, $data = null, $message = "")
    {
        $this->statusCode = $status;
        $this->message = $message;
        $this->data = $data;
    }
    public static function __set_state($data)
    {
        $obj = new ApiResponse();
        $obj->data = $data["data"];
        $obj->message = $data["message"];
        $obj->statusCode = $data["statusCode"];
        return $obj;
    }

    /**
    * This is the abstract method which returns json encoded data
    */
    function jsonSerialize()
    {
        if (is_null($this->data)) {
            $this->data  = new \stdClass();
        }
        return [
            'statusCode' => $this->statusCode,
            'message' => $this->message,
            'data' => $this->data
                
        ];
    }
}

问题原因

  1. PHP版本升级:PHP 8.x对JSON序列化的类型处理更严格,PDO扩展的类型映射也更精准,会保留数据库返回的整数类型为PHP的int,而PHP 7.3中可能默认将数值隐式转为字符串。
  2. Yii框架升级:Yii 2.0.51优化了数据库组件的类型映射逻辑,不再自动将整数转为字符串,直接返回原始数值类型。
  3. MariaDB版本升级:新版本数据库驱动对存储过程返回的字段类型识别更准确,确保i.id(整数类型)以数值形式传递给PHP,而非旧版本可能出现的字符串转换。

三者共同作用下,原本被隐式转为字符串的institutionId现在以整数类型输出到JSON响应中。

全局修复方案

方案1:PDO全局字符串化查询结果

在Yii数据库配置中添加PDO::ATTR_STRINGIFY_FETCHES属性,强制所有查询结果转为字符串:

// 数据库配置文件(如config/db.php)
'db' => [
    'class' => 'yii\db\Connection',
    'dsn' => 'mysql:host=localhost;dbname=your_db',
    'username' => 'root',
    'password' => 'your_pwd',
    'charset' => 'utf8mb4',
    'attributes' => [
        PDO::ATTR_STRINGIFY_FETCHES => true, // 全局将数值转为字符串
    ],
],

优点:无需修改业务代码,一次性解决所有字段类型问题;注意:若业务中有依赖数值类型的计算逻辑,需手动将字符串转为整数后再处理。

方案2:修改API响应序列化逻辑

在ApiResponse类的jsonSerialize方法中,递归遍历响应数据,将所有以Id结尾的整数字段转为字符串:

class ApiResponse implements \JsonSerializable
{
    // 原有属性和构造方法不变...

    function jsonSerialize()
    {
        if (is_null($this->data)) {
            $this->data = new \stdClass();
        }
        // 处理所有Id结尾的整数字段
        $processedData = $this->convertIdFieldsToString($this->data);
        return [
            'statusCode' => $this->statusCode,
            'message' => $this->message,
            'data' => $processedData
        ];
    }

    /**
     * 递归转换所有Id结尾的整数字段为字符串
     */
    private function convertIdFieldsToString($data)
    {
        if (is_object($data)) {
            foreach ($data as $key => $value) {
                if (preg_match('/Id$/', $key) && is_int($value)) {
                    $data->$key = (string)$value;
                } elseif (is_object($value) || is_array($value)) {
                    $data->$key = $this->convertIdFieldsToString($value);
                }
            }
            return $data;
        } elseif (is_array($data)) {
            foreach ($data as $key => $value) {
                if (preg_match('/Id$/', $key) && is_int($value)) {
                    $data[$key] = (string)$value;
                } elseif (is_object($value) || is_array($value)) {
                    $data[$key] = $this->convertIdFieldsToString($value);
                }
            }
            return $data;
        }
        return $data;
    }
}

优点:仅修改响应层,不影响数据库查询和业务逻辑;注意:需确保所有需要转换的ID字段命名符合xxxId格式。

方案3:自定义数据库结果处理器

创建自定义的DbCommand类,重写queryAll方法,统一转换整数类型字段为字符串:

namespace app\components;

use yii\db\Command;

class CustomDbCommand extends Command
{
    public function queryAll($fetchMode = null)
    {
        $result = parent::queryAll($fetchMode);
        return $this->convertNumericFieldsToString($result);
    }

    private function convertNumericFieldsToString($data)
    {
        if (is_array($data)) {
            foreach ($data as &$row) {
                if (is_array($row)) {
                    foreach ($row as &$value) {
                        if (is_int($value)) {
                            $value = (string)$value;
                        }
                    }
                }
            }
        }
        return $data;
    }
}

然后在数据库配置中指定commandClass:

'db' => [
    'class' => 'yii\db\Connection',
    'commandClass' => 'app\components\CustomDbCommand',
    // 其他配置...
],

优点:在数据库查询层统一处理,业务代码无需改动;注意:需考虑性能影响,尤其是大数据量查询时。


内容的提问来源于stack exchange,提问作者Meghana S Kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 04:42:04