Já vi essa pergunta ser repetida algumas vezes no Stack Overflow, mas nenhuma explora suficientemente o problema (ou pelo menos de uma forma que seja útil para mim)
O problema é que uma consulta de banco de dados deve retornar tipos de dados inteiros em PHP para colunas inteiras. Em vez disso, a consulta retorna cada coluna como um tipo de string.
Eu assegurei que "PDO :: ATTR_STRINGIFY_FETCHES" seja falso apenas para ter certeza de que os resultados não estão sendo convertidos em string.
Respostas que tenho visto:
- Não pode ser feito
- Não, está funcionando em Mac OS X instalado em PHP / MySQL
- Digite elenco de todos os seus valores em seu código
- Não, eu não vou fazer isso
- Não se preocupe com isso, o PHP é mal digitado
- Meus dados são enviados como JSON e são consumidos por muitos outros serviços, alguns requerem os dados no formato correto
Pela minha pesquisa, entendo que este é um problema de implementação do driver.
Muitas fontes afirmam que o driver nativo do MySQL não suporta o retorno de tipos numéricos. Isso não parece verdade, pois funciona no Mac OS X. A menos que eles digam que "o driver nativo do MySQL no Linux não suporta o recurso".
Isso implica que há algo especial sobre o driver / ambiente que instalei no Mac OS X. Tenho tentado identificar as diferenças para aplicar uma correção, mas estou limitado por meu conhecimento de como verificar essas coisas.
As diferenças:
- PHP no OS X foi compilado e instalado através do Home Brew
- PHP no Ubuntu foi instalado via "apt-get install php5-dev"
- PHP no OS X está se conectando a um servidor MySQL também rodando no OS X
- Versão do servidor: 5.1.71-log de distribuição de origem
- PHP no Ubuntu está se conectando a um banco de dados Rackspace Cloud
- Versão do servidor: 5.1.66-0 + squeeze1 (Debian)
Ambiente Ubuntu
- Versão: 10.04.1
- PHP 5.4.21-1 + debphp.org ~ lucid + 1 (cli) (construído em: 21 de outubro de 2013 08:14:37)
php -i
pdo_mysql
Driver PDO para MySQL => versão API do cliente habilitada => 5.1.72
Ambiente Mac OS X
- 10.7.5
- PHP 5.4.16 (cli) (construído em: 22 de agosto de 2013 09:05:58)
php -i
pdo_mysql
Driver PDO para MySQL => versão API do cliente habilitada => mysqlnd 5.0.10 - 20111026 - $ Id: e707c415db32080b3752b232487a435ee0372157 $
Sinalizadores PDO usados
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,
Qualquer ajuda e conhecimento seriam apreciados :) Definitivamente estarei postando de volta aqui se eu encontrar a resposta.
Respostas:
A solução é garantir que você está usando o driver mysqlnd para php.
Como você sabe que não está usando o mysqlnd?
Ao visualizar
php -i
, não haverá nenhuma menção de "mysqlnd". Apdo_mysql
seção terá algo assim:pdo_mysql PDO Driver for MySQL => enabled Client API version => 5.1.72
Como você instala?
A maioria dos guias de instalação para L / A / M / P sugerem
apt-get install php5-mysql
mas o controlador nativo para MySQL é instalado por um pacote diferente:php5-mysqlnd
. Descobri que isso estava disponível com o ppa: ondrej / php5-oldstable .Para mudar para o novo driver (no Ubuntu):
apt-get remove php5-mysql
apt-get install php5-mysqlnd
service apache2 restart
Como verifico se o driver está sendo usado?
Agora
php -i
mencionarei "mysqlnd" explicitamente napdo_mysql
seção:pdo_mysql PDO Driver for MySQL => enabled Client API version => mysqlnd 5.0.10 - 20111026 - $Id: e707c415db32080b3752b232487a435ee0372157 $
Configurações de PDO
Certifique-se de que
PDO::ATTR_EMULATE_PREPARES
éfalse
(verifique seus padrões ou defina-o):$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
Certifique-se de que
PDO::ATTR_STRINGIFY_FETCHES
éfalse
(verifique seus padrões ou defina-o):$pdo->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);
Valores retornados
† BIGINTs com um valor maior que um int assinado de 64 bits (9223372036854775807) retornarão como uma string (ou 32 bits em um 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)
fonte
0.30
em"0.30"
vez de0.3
. Decimais são usados para isso ... então este é o comportamento corretoPDO::ATTR_EMULATE_PREPARES
usar um parâmetro nomeado mais de uma vezEssa resposta aceita funciona e parece ser a resposta mais popular no Google para essa pergunta. Meu problema é que preciso implantar um aplicativo em vários ambientes e nem sempre consigo instalar o driver correto, além disso, preciso que os decimais sejam numéricos, não sequências. Portanto, criei uma rotina para digitar maiúsculas e minúsculas antes da codificação JSON, que é facilmente modificada para se adequar. É meio como explodir em órbita.
Primeiro, use "mostrar colunas de" para obter as colunas da tabela. consulta mysql "MOSTRAR COLUNAS DA tabela como 'nomedocolmun'": questões
$query = 'SHOW COLUMNS FROM ' . $table; //run with mysqli or PDO
Em seguida, coloque os tipos em uma matriz indexada pelo nome da coluna para facilitar a iteração. Assume que o conjunto de resultados de colunas de exibição está em uma variável chamada $ colunas_de_tabela. http://php.net/manual/en/function.array-column.php
$column_types = array_column( $columns_from_table, 'Type', 'Field');
Em seguida, queremos remover o parênteses do tipo, que será algo como varchar (32) ou decimal (14,6)
foreach( $column_types as $col=>$type ) { $len = strpos( $type, '(' ); if( $len !== false ) { $column_types[ $col ] = substr( $type, 0, $len ); } }
Agora temos uma matriz associada com o nome da coluna como o índice e o tipo formatado como o valor, por exemplo:
Array ( [id] => int [name] => varchar [balance] => decimal ... )
Agora, quando você faz sua seleção na tabela, pode iterar os resultados e converter o valor para o tipo apropriado:
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; }
A instrução switch pode ser facilmente modificada para se adequar e pode incluir funções de data, etc. Por exemplo, no meu caso, um terceiro está inserindo valores de moeda no banco de dados como um decimal, mas quando eu pego esses dados e preciso retorná-los como JSON, preciso que sejam números, não strings.
Testado com PHP 7, 7.2 e JQuery 2, 3.
fonte