He visto repetirse esta pregunta varias veces en Stack Overflow, pero ninguna explora suficientemente el problema (o al menos de una manera que me sea útil)
El problema es que una consulta de base de datos debería devolver tipos de datos enteros en PHP para columnas enteras. En cambio, la consulta devuelve cada columna como un tipo de cadena.
Me he asegurado de que "PDO :: ATTR_STRINGIFY_FETCHES" sea falso solo para asegurarme de que los resultados no se conviertan en cadenas.
Respuestas que he visto:
- No se puede hacer
- No, está funcionando en Mac OS X instalado PHP / MySQL
- Escriba emitir todos sus valores en su código
- No, no haré eso
- No se preocupe por eso, PHP está escrito de manera flexible
- Mis datos se envían como JSON y son consumidos por muchos otros servicios, algunos requieren los datos en el formato correcto
De mi investigación, entiendo que este es un problema de implementación de controladores.
Muchas fuentes afirman que el controlador nativo de MySQL no admite la devolución de tipos numéricos. Esto no parece cierto ya que funciona en Mac OS X. A menos que quieran decir que "el controlador nativo de MySQL en Linux no es compatible con la función".
Esto implica que hay algo especial en el controlador / entorno que he instalado en Mac OS X. He estado tratando de identificar las diferencias para aplicar una solución, pero estoy limitado por mi conocimiento de cómo verificar estas cosas.
Las diferencias:
- PHP en OS X se compiló e instaló a través de Home Brew
- PHP en Ubuntu se instaló a través de "apt-get install php5-dev"
- PHP en OS X se está conectando a un servidor MySQL que también se ejecuta en OS X
- Versión del servidor: distribución de origen 5.1.71-log
- PHP en Ubuntu se está conectando a una base de datos en la nube de Rackspace
- Versión del servidor: 5.1.66-0 + squeeze1 (Debian)
Entorno Ubuntu
- Versión: 10.04.1
- PHP 5.4.21-1 + debphp.org ~ lucid + 1 (cli) (construido: 21 de octubre de 2013 08:14:37)
php -i
pdo_mysql
Controlador PDO para MySQL => versión API de cliente habilitada => 5.1.72
Entorno Mac OS X
- 10.7.5
- PHP 5.4.16 (cli) (construido: 22 de agosto de 2013 09:05:58)
php -i
pdo_mysql
Controlador PDO para MySQL => versión de API de cliente habilitada => mysqlnd 5.0.10 - 20111026 - $ Id: e707c415db32080b3752b232487a435ee0372157 $
Indicadores de DOP utilizados
PDO::ATTR_CASE => PDO::CASE_NATURAL,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,
PDO::ATTR_STRINGIFY_FETCHES => false,
PDO::ATTR_EMULATE_PREPARES => false,
Se agradecería cualquier ayuda y experiencia :) Definitivamente volveré a publicar aquí si encuentro la respuesta.
Respuestas:
La solución es asegurarse de que está utilizando el controlador mysqlnd para php.
¿Cómo sabe que no está usando mysqlnd?
Cuando se ven
php -i
, no habrá ninguna mención de "mysqlnd". Lapdo_mysql
sección tendrá algo como esto:pdo_mysql PDO Driver for MySQL => enabled Client API version => 5.1.72
¿Cómo lo instalas?
La mayoría de las guías de instalación de L / A / M / P sugieren
apt-get install php5-mysql
pero el controlador nativo de MySQL se instala mediante un paquete diferente:php5-mysqlnd
. Descubrí que esto estaba disponible con ppa: ondrej / php5-oldstable .Para cambiar al nuevo controlador (en Ubuntu):
apt-get remove php5-mysql
apt-get install php5-mysqlnd
service apache2 restart
¿Cómo verifico que se esté utilizando el controlador?
Ahora
php -i
mencionaré "mysqlnd" explícitamente en lapdo_mysql
sección:pdo_mysql PDO Driver for MySQL => enabled Client API version => mysqlnd 5.0.10 - 20111026 - $Id: e707c415db32080b3752b232487a435ee0372157 $
Configuración de PDO
Asegúrese de que
PDO::ATTR_EMULATE_PREPARES
seafalse
(verifique sus valores predeterminados o configúrelo):$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
Asegúrese de que
PDO::ATTR_STRINGIFY_FETCHES
seafalse
(verifique sus valores predeterminados o configúrelo):$pdo->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);
Valores devueltos
† Los BIGINT con un valor mayor que un int con signo de 64 bits (9223372036854775807) regresarán como una cadena (o 32 bits en un sistema de 32 bits)
object(stdClass)[915] public 'integer_col' => int 1 public 'double_col' => float 1.55 public 'float_col' => float 1.5 public 'decimal_col' => string '1.20' (length=4) public 'bigint_col' => string '18446744073709551615' (length=20)
fuente
0.30
como en"0.30"
lugar de0.3
. Los decimales se utilizan para esto ... así que este es el comportamiento correctoPDO::ATTR_EMULATE_PREPARES
usar un parámetro con nombre más de una vezEsta respuesta aceptada funciona y parece ser la respuesta más popular en Google para esta pregunta. Mi problema es que necesito implementar una aplicación en múltiples entornos y no siempre tengo la capacidad de instalar el controlador correcto, además necesito que los decimales sean numéricos, no cadenas. Así que creé una rutina para escribir mayúsculas y minúsculas antes de la codificación JSON, que se modifica fácilmente para adaptarse. Es como destruirlo desde la órbita.
Primero, use "mostrar columnas de" para obtener las columnas de la tabla. consulta de mysql "MOSTRAR COLUMNAS DE la tabla como 'colmunname'": preguntas
$query = 'SHOW COLUMNS FROM ' . $table; //run with mysqli or PDO
Luego, coloque los tipos en una matriz indexada por el nombre de la columna para facilitar la iteración. Supone que el conjunto de resultados de mostrar columnas está en una variable denominada $ columnas_de_tabla. http://php.net/manual/en/function.array-column.php
$column_types = array_column( $columns_from_table, 'Type', 'Field');
A continuación, queremos eliminar el paréntesis del tipo, que será algo así como varchar (32) o decimal (14,6).
foreach( $column_types as $col=>$type ) { $len = strpos( $type, '(' ); if( $len !== false ) { $column_types[ $col ] = substr( $type, 0, $len ); } }
Ahora tenemos una matriz asociada con el nombre de la columna como índice y el tipo formateado como valor, por ejemplo:
Array ( [id] => int [name] => varchar [balance] => decimal ... )
Ahora, cuando haga su selección de su tabla, puede iterar sobre los resultados y convertir el valor al tipo apropiado:
foreach( $results as $index=>$row ) { foreach( $row as $col=>$value ) { switch( $column_types[$col] ) { case 'decimal': case 'numeric': case 'float': case 'double': $row[ $col ] = (float)$value; break; case 'integer': case 'int': case 'bigint': case 'mediumint': case 'tinyint': case 'smallint': $row[ $col ] = (int)$value; break; } } $results[ $index ] = $row; }
La declaración de cambio se puede modificar fácilmente para adaptarse y podría incluir funciones de fecha, etc. Por ejemplo, en mi caso, un tercero está introduciendo valores de moneda en la base de datos como un decimal, pero cuando obtengo esos datos y necesito devolverlos como JSON, necesito que sean números, no cadenas.
Probado con PHP 7, 7.2 y JQuery 2, 3.
fuente