2008-10-27 12 views
240

Usando PHP, ¿cuál es la forma más rápida de convertir una cadena como esta: "123" a un número entero?La forma más rápida de convertir cadena a entero en PHP

¿Por qué es ese método en particular el más rápido? ¿Qué sucede si recibe una entrada inesperada, como "hello" o una matriz?

+1

proyecto de ley: no es tarea, en realidad tengo curiosidad. :) – nickf

+0

¿Por qué es relevante el "más rápido"? –

+12

bien si no duele (legibilidad), ¿por qué no hacer las cosas de la manera más eficiente posible? – nickf

Respuesta

364

Acabo de configurar un ejercicio de evaluación comparativa rápida:

Function    time to run 1 million iterations 
-------------------------------------------- 
(int) "123":    0.55029 
intval("123"):    1.0115 (183%) 

(int) "0":     0.42461 
intval("0"):    0.95683 (225%) 

(int) int:     0.1502 
intval(int):    0.65716 (438%) 

(int) array("a", "b"):  0.91264 
intval(array("a", "b")): 1.47681 (162%) 

(int) "hello":    0.42208 
intval("hello"):   0.93678 (222%) 

En promedio, llamando intval() es dos veces y medio más lento, y la diferencia es mayor si su entrada ya es un número entero .

Me gustaría saber por qué though.


Actualización: He ejecute las pruebas de nuevo, esta vez con la coacción (0 + $var)

| INPUT ($x)  | (int) $x |intval($x) | 0 + $x | 
|-----------------|------------|-----------|-----------| 
| "123"   | 0.51541 | 0.96924 | 0.33828 | 
| "0"    | 0.42723 | 0.97418 | 0.31353 | 
| 123    | 0.15011 | 0.61690 | 0.15452 | 
| array("a", "b") | 0.8893 | 1.45109 | err!  | 
| "hello"   | 0.42618 | 0.88803 | 0.1691 | 
|-----------------|------------|-----------|-----------| 

Adición: yo sólo he encontrado con un comportamiento ligeramente inesperado que se debe tener en cuenta cuando la elección de uno de estos métodos:

$x = "11"; 
(int) $x;  // int(11) 
intval($x); // int(11) 
$x + 0;  // int(11) 

$x = "0x11"; 
(int) $x;  // int(0) 
intval($x); // int(0) 
$x + 0;  // int(17) ! 

$x = "011"; 
(int) $x;  // int(11) 
intval($x); // int(11) 
$x + 0;  // int(11) (not 9) 

probada usando PHP 5.3.1

+9

Probablemente tenga algo que ver con el hecho de que intval() invoca una llamada a función, mientras que el reparto se maneja directamente en la calculadora de expresiones del intérprete. Esta también puede ser la razón por la que una co-erción es aún más rápida. – staticsan

+10

Su ejemplo de coerción puede simplificarse aún más utilizando el operador unario plus poco conocido de php. $ x + 0 -> + $ x – Ozzy

+0

@Ozzy Eso es increíble. ¡Gracias por el consejo! '+" 15 "== 15' – caiosm1005

15

Ejecuta una prueba.

string coerce:   7.42296099663 
    string cast:   8.05654597282 
    string fail coerce:  7.14159703255 
    string fail cast:  7.87444186211 

Esta fue una prueba que ejecutó cada escenario 10,000,000 de veces. :-)

Co-ercion es 0 + "123"

fundición se (integer)"123"

Creo Co-ercion es un poquito más rápido. Ah, y tratando 0 + array('123') es un error fatal en PHP. Es posible que desee que su código verifique el tipo del valor suministrado.

Mi código de prueba está por debajo.


function test_string_coerce($s) { 
    return 0 + $s; 
} 

function test_string_cast($s) { 
    return (integer)$s; 
} 

$iter = 10000000; 

print "-- running each text $iter times.\n"; 

// string co-erce 
$string_coerce = new Timer; 
$string_coerce->Start(); 

print "String Coerce test\n"; 
for($i = 0; $i < $iter ; $i++) { 
    test_string_coerce('123'); 
} 

$string_coerce->Stop(); 

// string cast 
$string_cast = new Timer; 
$string_cast->Start(); 

print "String Cast test\n"; 
for($i = 0; $i < $iter ; $i++) { 
    test_string_cast('123'); 
} 

$string_cast->Stop(); 

// string co-erce fail. 
$string_coerce_fail = new Timer; 
$string_coerce_fail->Start(); 

print "String Coerce fail test\n"; 
for($i = 0; $i < $iter ; $i++) { 
    test_string_coerce('hello'); 
} 

$string_coerce_fail->Stop(); 

// string cast fail 
$string_cast_fail = new Timer; 
$string_cast_fail->Start(); 

print "String Cast fail test\n"; 
for($i = 0; $i < $iter ; $i++) { 
    test_string_cast('hello'); 
} 

$string_cast_fail->Stop(); 

// ----------------- 
print "\n"; 
print "string coerce:   ".$string_coerce->Elapsed()."\n"; 
print "string cast:   ".$string_cast->Elapsed()."\n"; 
print "string fail coerce:  ".$string_coerce_fail->Elapsed()."\n"; 
print "string fail cast:  ".$string_cast_fail->Elapsed()."\n"; 


class Timer { 
    var $ticking = null; 
    var $started_at = false; 
    var $elapsed = 0; 

    function Timer() { 
     $this->ticking = null; 
    } 

    function Start() { 
     $this->ticking = true; 
     $this->started_at = microtime(TRUE); 
    } 

    function Stop() { 
     if($this->ticking) 
      $this->elapsed = microtime(TRUE) - $this->started_at; 
     $this->ticking = false; 
    } 

    function Elapsed() { 
     switch($this->ticking) { 
      case true: return "Still Running"; 
      case false: return $this->elapsed; 
      case null: return "Not Started"; 
     } 
    } 
} 
+0

Agregué 'settype' a esta prueba y la ejecuté usando PHP 7. El molde salió un poco adelante y una gran mejora en el rendimiento: coerción de cadena: 1.9255340099335 cadena de reparto: 1.5142338275909 cadena settype: 4.149735212326 cadena falle coaccionar: 1.2346560955048 cadena falle fundido: 1.3967711925507 cadena falle settype: 4.149735212326 – bstoney

32

me siento personalmente de fundición es la más bonita.

$iSomeVar = (int) $sSomeOtherVar; 

En caso de que una cadena como 'Hola' ser enviado, se echó a un entero 0. Para una cadena como '22 años', que será lanzado a un entero 22. Cualquier cosa que no se puede analizar a un número se convierte en 0.

Si realmente NECESITA la velocidad, supongo que las otras sugerencias aquí son correctas al asumir que la coacción es la más rápida.

+7

curiosamente, las matrices quedan echados a 1. Figura marcha. – nickf

+2

@nickf No es así - Se puede convertir a 0 también. Lanza su valor booleano (verdadero | falso) a un entero - 'falso' = 0, 'verdadero' = 1. Una matriz es falsa si está 100% vacía, y es verdadera si contiene CUALQUIER dato, incluso si está vacío cadenas o valores NULL Si tuvieras que lanzar un conjunto vacío a un número entero, se convertiría en 0. (Sí, estoy al tanto de esto!) –

7
$int = settype("100", "integer"); //convert the numeric string to int 
+3

¡Creo que hay alguna referencia o prueba en regla! – Mehran

+0

$ int en realidad sería un booleano aquí, si la declaración funcionó, pero no lo haría ya que el primer parámetro de settype() se pasa por referencia, por lo que debe ser una var. – Queue

9

Simplemente puede convertir una cadena larga en número entero mediante el uso de FLOAT

$float = (float)$num;

O si desea número entero no flotante val luego ir con

$float = (int)$num;

Por ej.

(int) "1212.3" = 1212 
(float) "1212.3" = 1212.3 
+1

¿Eh? Si quieres un int, ¿por qué no usarías '(int)'? Puede ser cierto que si la cadena contiene un entero, ese '(float)' devolverá un valor que actúa como un entero (aunque su tipo interno probablemente sea 'float'), pero ¿por qué haría esto, si la especificación es para devolver un valor entero? Supongamos que la cadena entrante es "1.3"? No obtendrás un número entero. Además, por el bien de cualquiera que lea el código en el futuro, debe decir lo que quiere decir. Si quiere decir "debería ser un número entero", entonces diga '(int)', not '(float)'. – ToolmakerSteve

3

más ad-hoc resultados de referencia:

$ time php -r 'for ($x = 0;$x < 999999999; $x++){$i = (integer) "-11";}'  

real 2m10.397s 
user 2m10.220s 
sys  0m0.025s 

$ time php -r 'for ($x = 0;$x < 999999999; $x++){$i += "-11";}'    

real 2m1.724s 
user 2m1.635s 
sys  0m0.009s 

$ time php -r 'for ($x = 0;$x < 999999999; $x++){$i = + "-11";}'    

real 1m21.000s 
user 1m20.964s 
sys  0m0.007s 
+0

Sería mejor escribir el enunciado que se está probando 10 veces en cada ciclo, para que el tiempo no esté dominado por la sobrecarga del ciclo. P.ej. '{$ i = +" - 11 "; $ i = + "- 11"; $ i = + "- 11"; $ i = + "- 11"; ...} '. También es riesgoso usar el valor literal '" -11 "' directamente, a menos que esté seguro de que el lenguaje no hará parte del trabajo en tiempo de compilación. Probablemente esté bien para un lenguaje dinámico como PHP, pero menciono para referencia futura si prueba fórmulas en otros idiomas. Más seguro para establecer una variable '$ x =" -11 "' antes del ciclo de prueba, y luego usarlo. Entonces, el código interno es '$ i = + $ x'. – ToolmakerSteve

7

número entero excract de cualquier cadena

$ en = 'tel.123-12-33';

preg_match_all('!\d+!', $in, $matches); 
$out = (int)implode('', $matches[0]); 

// $ out = '1231233';

+0

¡Eres el mejor de lo mejor de lo mejor! He pasado horas para convertir algunas var de cadena de datos json a entero, ¡solo tu método ayudó! ¡gracias! – Kamnibula

3

Ran un punto de referencia, y resulta que la manera más rápida de conseguir una verdadera número entero (utilizando todos los métodos disponibles) es

$foo = (int)+"12.345"; 

Simplemente usando

$foo = +"12.345"; 

devuelve un flotador.

+1

Esto es más rápido que simplemente '(int)" 12.345 "'? Más rápido en qué porcentaje? – ToolmakerSteve

Cuestiones relacionadas