2009-09-07 18 views
112

Tengo un problema con la función PHP json_encode. Codifica los números como cadenas, p.PHP json_encode codificando números como cadenas

array('id' => 3) 

convierte

"{ ["id": "3", ...) 

Cuando js se encuentra con estos valores, que los interpreta como cuerdas y operaciones numéricas fallan en ellos. ¿Alguien sabe alguna forma de evitar que json_encode codifique números como cadenas? ¡Gracias!

+0

Estaba teniendo el mismo problema y pude resolver el mío utilizando los mutadores de Laravel en el modelo. Te permite modificar los valores en el modelo. http://laravel.com/docs/eloquent#accessors-and-mutators Al principio no lo entendí del todo, pero esta pregunta me ayudó: http://stackoverflow.com/questions/16985656/laravel-problems-with- mutators – Jazzy

+0

Resulta que este es un problema específico de la versión. A veces, un tirón de una base de datos MySql mantendrá los tipos correctos. En versiones anteriores, puede devolver todo como una cadena. Lo escribí esta mañana. http://shakyshane.com/blog/output-json-from-php.html – shane

Respuesta

23

que he hecho una prueba muy rápida:

$a = array(
    'id' => 152, 
    'another' => 'test', 
    'ananother' => 456, 
); 
$json = json_encode($a); 
echo $json; 

Ésta parece ser como lo que se describir, si no estoy equivocado?

y me estoy poniendo como salida:

{"id":152,"another":"test","ananother":456} 

Por lo tanto, en este caso, los números enteros no han sido convertidos en cadena.


Sin embargo, esto podría ser dependiente de la versión de PHP que estamos utilizando: ha habido un par de errores relacionados con json_encode corregido, dependiendo de la versión de PHP ...

Esta prueba se ha hecho con PHP 5.2.6; Estoy obteniendo lo mismo con PHP 5.2.9 y 5.3.0; No tengo otra versión 5.2.x para probar con, aunque :-(

¿Qué versión de PHP está usando? ¿O es su caso de prueba más compleja que el ejemplo que has publicado?

Tal vez uno informe de error http://bugs.php.net/ podría estar relacionado? Por ejemplo, Bug #40503 : json_encode integer conversion is inconsistent with PHP?


Tal Bug #38680 podría interesarle también, por cierto?

+0

Gracias Martin. Estoy usando 5.2.9. Me pregunto si los datos numéricos se leen del DB como una cadena. Estoy seguro de que los tipos de campo son int, pero no puedo pensar en otra explicación. Probaré tu prueba rápida en mi sistema y veré si obtengo el mismo resultado. –

+1

Obtuve el mismo resultado que usted. Me pregunto por qué PHP –

+9

OK acerca de 5.2.9; si sus datos provienen de una base de datos, el problema podría estar allí: a menudo he visto datos provenientes de la base de datos con todo en casteo (he visto esto con PDO y mssql; pero, si mal no recuerdo, esto también ocurre) para MySQL en PHP <5.3, cuando el nuevo controlador mysqlnd aún no existía) ;; Para comprobar cómo se ven sus datos, puede usar var_dump, que genera los tipos de cada parte de los datos. –

-2

json_encode serializa alguna estructura de datos en formato JSON para enviar a través de la red. Por lo tanto, todo el contenido será del tipo cadena. Al igual que cuando recibe algún parámetro de $ _POST o $ _GET.

Si tiene que realizar operaciones numéricas en los valores enviados, simplemente conviértalos a int primero (con el intval() function en PHP o parseInt() en Javascript) y luego ejecute las operaciones.

+0

eso no es de lo que está hablando. él está hablando de que el json tiene comillas dobles alrededor de los números. – JasonWoof

+0

En el caso de JSON, conserva tipos. Imagine escribir un Objeto de JavaScript literal, cualquier valor entre comillas se convierte en cadenas, pero los números no citados se vuelven enteros, 0x [0-9a-z] se convierte en hexadecimal, etc.Hay diferencias de tipo con PHP, como, por ejemplo, no existe una matriz asociativa, solo objetos o matrices indexadas, etc. – bucabay

+0

derecha. El problema que estaba teniendo era que tenía una variable php, que pensaba que tenía tipo int, porque venía de una columna DB de tipo int. Pero, de hecho, la variable PHP tenía una cadena tipo, por lo tanto, las comillas en el JSON. – JasonWoof

-1

Bueno, PHP json_encode() devuelve una cadena.

Puede utilizar parseFloat() o parseInt() en el código JS sin embargo:

parseFloat('122.5'); // returns 122.5 
parseInt('22'); // returns 22 
parseInt('22.5'); // returns 22 
+0

Gracias. Esperaba que hubiera un método más elegante. –

+1

Sí, la forma más segura es analizarlos. pero, de nuevo, ¿Javascript no está vagamente escrito? – mauris

+0

Solo un comentario: está tipeado libremente, aún el resultado de "1" +1 será ... 11 - así que usando JS deberías ser más atento que en los lenguajes de tipo fuerte, porque te advertirán, JS simplemente hace qué es mejor si se manejan números de cadena ... – SamiSalami

8

estoy encontrando el mismo problema (PHP-5.2.11/Windows). yo Estoy usando esta solución

$json = preg_replace("/\"(\d+)\"/", '$1', $json); 

que sustituye a todos los números (no negativo, entero) entre comillas con el número en sí ('42 "' se convierte en '42').

Véase también this comment in PHP manual.

+0

Gracias por el código, pero lamentablemente no lo hizo trabajar en mi json porque tengo un número como nombre de objeto, y parece hacer que el json no sea válido :( –

+0

@SSHEsto, tal vez deberías usar esta sintaxis para convertir la matriz en una matriz codificada JSON y no en un objeto. ' $ json_array = json_encode ($ some_array, false); ' Entonces, el falso argumento le dice a PHP que no haga la conversión del objeto. – hyde

+0

No es seguro usar esa solución.Obtendrás json no válido con estructuras como esa: 'json_encode (array (-1 => 'que', '0' => '- 1'))' –

3

La siguiente prueba confirma que el cambio del tipo de cadena provoca json_encode() para devolver un valor numérico como una cadena JSON (es decir, rodeada por comillas dobles). Use settype (arr ["var"], "integer") o settype ($ arr ["var"], "float") para arreglarlo.

<?php 

class testclass { 
    public $foo = 1; 
    public $bar = 2; 
    public $baz = "Hello, world"; 
} 

$testarr = array('foo' => 1, 'bar' => 2, 'baz' => 'Hello, world'); 

$json_obj_txt = json_encode(new testclass()); 
$json_arr_txt = json_encode($testarr); 

echo "<p>Object encoding:</p><pre>" . $json_obj_txt . "</pre>"; 
echo "<p>Array encoding:</p><pre>" . $json_arr_txt . "</pre>"; 

// Both above return ints as ints. Type the int to a string, though, and... 
settype($testarr["foo"], "string"); 
$json_arr_cast_txt = json_encode($testarr); 
echo "<p>Array encoding w/ cast:</p><pre>" . $json_arr_cast_txt . "</pre>"; 

?> 
0

También tuve el mismo problema al procesar los datos de la base de datos. Básicamente, el problema es que el tipo en la matriz para convertir en json, es reconocido por PHP como una cadena y no como un entero. En mi caso realicé una consulta que devuelve datos de una fila de recuento de columnas DB. El controlador PDO no reconoce la columna como int, sino como cadenas. Lo resolví realizando un lanzamiento como int en la columna afectada.

273

Tenga en cuenta que a partir de PHP 5.3.3, there's a flag para los números de auto-conversión (el parámetro de opciones fue agregado en PHP 5.3.0):

$arr = array('row_id' => '1', 'name' => 'George'); 
echo json_encode($arr, JSON_NUMERIC_CHECK); // {"row_id":1,"name":"George"} 
+4

Tenga en cuenta que JSON_NUMERIC_CHECK requiere PHP 5.3.3. – Robert

+0

me ayudó, gracias. –

+8

Funcionó perfecto hasta que arrojó una etiqueta numérica a un número entero, explotando .toLowerCase() en IE. Tenga cuidado, esta solución es simple pero demasiado entusiasta. –

0

En aras de la exhaustividad (ya que no se puede añadir comentarios aún), permítame también agregar este detalle como otra respuesta:

(Editar: para leer después de darse cuenta de que los datos de origen (es decir, en el caso del OP, conjunto de resultados de la base de datos) podrían ser el problema (devolviendo columnas numéricas como cuerdas), y json_encode() en realidad no era el origen del problema)

páginas

Manual de ambos "mysql_fetch_array ":

devuelve una matriz de cadenasque corresponde a la fila recuperada,

... y" mysql_ fetch_ row":

Devuelve un numérico matriz de cadenas que corresponde a la descabellada fila

establece claramente que; las entradas en la matriz devuelta serán cadenas.

(que estaba usando la clase DB en phpBB2 (sí, lo sé, es obsoleto!), Y "sql_fetchrow()" método de esa clase usa "mysql_fetch_array()")

Sin darse cuenta de esto, también ¡Terminé encontrando esta pregunta y entendiendo el problema! :)

Como dijo Pascal Martin arriba en sus comentarios de seguimiento, creo que una solución que soluciona el problema del "tipo incorrecto" en la fuente (es decir, usando la función "mysql_field_type()" y haciendo el molde justo después fetch, (u otros métodos de búsqueda como "objeto"?)) sería el mejor en general.

28

Yo, también estaba leyendo de un DB (PostgreSQL) y todo era una cadena.Nos bucle sobre cada fila y hacer cosas con él para construir nuestra array resultados final, así que utilizamos

$result_arr[] = array($db_row['name'], (int)$db_row['count']); 

dentro del bucle para forzarlo a ser un valor entero. Cuando hago json_encode($result_arr) ahora, lo formatea correctamente como un número. Esto le permite controlar qué es y qué no es un número proveniente de su base de datos.

EDIT:

La función json_encode() también tiene la capacidad de hacerlo sobre la marcha utilizando la bandera JSON_NUMERIC_CHECK como segundo argumento a ella. Usted necesita tener cuidado de usar, aunque como se muestra en este ejemplo los usuarios en la documentación (copiado a continuación): http://uk3.php.net/manual/en/function.json-encode.php#106641

<?php 
// International phone number 
json_encode(array('phone_number' => '+33123456789'), JSON_NUMERIC_CHECK); 
?> 

Y entonces se obtiene este JSON:

{"phone_number":33123456789} 
+1

buena respuesta. Me ayudó –

+0

sí, parece que el problema está en el adaptador DB que no interpreta los tipos de datos, NO en la función 'json_encode'. esta es la respuesta más correcta, pero ten cuidado ya que 'JSON_NUMERIC_CHECK' convierte también números de teléfono y otros valores numéricos de cadena, y esto podría dar problemas en ceros a la izquierda o '+' ... ** Sugiero corregir este problema en la lectura de DB función. ** – caesarsol

-1
$rows = array(); 
while($r = mysql_fetch_assoc($result)) { 
    $r["id"] = intval($r["id"]); 
    $rows[] = $r; 
} 
print json_encode($rows); 
-1

Sólo tiene que ejecutar en el mismo problema y fue la base de datos que devolvió los valores como cadenas.

Puedo usar esto como una solución:

$a = array(
    'id' => $row['id'] * 1, 
    'another' => ..., 
    'ananother' => ..., 
); 
$json = json_encode($a); 

Eso está multiplicando el valor en 1 para su emisión en un número

la esperanza de que ayude a alguien

+0

utilizando un multiplicador no es la solución más eficiente. considere usar JSON_NUMERIC_CHECK en json_encode ya que lo arreglará automáticamente – Erick

-2

Como oli_arborum dijo, creo que se puede usar un preg_replace para hacer el trabajo. Sólo cambia el orden como la siguiente:

$json = preg_replace('#:"(\d+)"#', ':$1', $json); 
0

es la versión php el problema, tenía el mismo problema actualizar mi versión de PHP a 5,6 resuelto el problema

0

casting los valores a un int o float parece solucionarlo . Por ejemplo:

$coordinates => array( 
    (float) $ap->latitude, 
    (float) $ap->longitude 
); 
0

¡Puede usar (int) si ocurre algún problema! Funcionará bien.

0

Así que Pascal MARTIN no está recibiendo suficiente crédito aquí. La comprobación de valores numéricos en cada devolución JSON no es factible para un proyecto existente con cientos de funciones del lado del servidor.

Reemplacé php-mysql con php-mysqlnd, y el problema desapareció. Los números son números, las cadenas son cadenas, los booleanos son booleanos.