Maneira mais rápida de converter string para inteiro em PHP


251

Usando PHP, qual é a maneira mais rápida de converter uma string como esta: "123"para um número inteiro?

Por que esse método específico é o mais rápido? O que acontece se obtém entrada inesperada, como "hello"ou uma matriz?


12
bem, se não machuca (legibilidade), por que não fazer as coisas da maneira mais eficiente possível?
nickf

19
Se não prejudica a velocidade, por que não fazer as coisas da maneira mais legível possível?
Andy Lester

4
@ Andy, veja os testes de benchmark abaixo. A diferença entre (int)e intval()pode ser superior a 400%!
#

6
o mais rápido é importante porque a velocidade é importante para a experiência do usuário. Quando você tem muitas operações em andamento, você quer que elas sejam RÁPIDAS!
Philipp

13
sem chutar um cavalo morto, eu diria também que a questão da velocidade versus legibilidade é irrelevante nesse caso, porque a questão foi marcada como otimização. A razão para querer velocidade em uma pergunta marcada como otimização é auto-explicativa.
TotallyNotLizards

Respostas:


371

Acabei de configurar um rápido exercício de benchmarking:

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%)

Em média, chamar intval () é duas vezes e meia mais lenta e a diferença é maior se sua entrada já for um número inteiro.

Eu estaria interessado em saber o porquê .


Atualização: Eu executei os testes novamente, desta vez com coerção (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   |
|-----------------|------------|-----------|-----------|

Adendo: acabei de me deparar com um comportamento ligeiramente inesperado, que você deve conhecer ao escolher um destes 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)

Testado usando o PHP 5.3.1


9
Provavelmente tem algo a ver com o fato de intval () chamar uma chamada de função, enquanto o elenco é tratado diretamente na calculadora de expressão do intérprete. Essa também pode ser a razão pela qual uma cooperação é ainda mais rápida.
Staticsan 27/10/08

10
Seu exemplo de coerção pode ser ainda mais simplificado usando o operador unário mais pouco conhecido do php. $ x + 0 -> + $ x
Ozzy

@ Ozzy Isso é incrível. Obrigado pela dica! +"15" == 15
#

1
@ John, uma vez que ele testa apenas dois casos nesse primeiro código (int)e intval, em cada par, fornece um% intval, o caso base deve ser (int). Mas você tem um bom argumento de que teria ficado mais claro se ele tivesse dito isso explicitamente, especialmente desde que ele acrescentou mais tarde um terceiro caso!
Página

2
Existe alguma alteração nesses resultados nas versões mais recentes do PHP?
Artyom

34

Pessoalmente, acho que o elenco é o mais bonito.

$iSomeVar = (int) $sSomeOtherVar;

Se uma string como 'Hello' for enviada, ela será convertida em número inteiro 0. Para uma string como '22 anos ', será convertida em número inteiro 22. Qualquer coisa que não puder analisar um número se tornará 0.

Se você realmente PRECISA da velocidade, acho que as outras sugestões aqui estão corretas ao assumir que a coerção é a mais rápida.


7
curiosamente, as matrizes são convertidas em 1. vão entender.
nickf

2
@nickf Não é assim - pode ser convertido para 0 também. Ele lança seu valor booleano (true | false) para um número inteiro - 'false' = 0, 'true' = 1. Uma matriz é falsa se estiver 100% vazia e é verdadeira se contiver QUALQUER dado, mesmo que esteja vazia. cadeias ou valores NULL. Se você fosse para lançar um array vazio para um inteiro, que se tornaria 0. (Sim, eu estou ciente dessa idade!)
Super Cat

15

Execute um teste.

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

Este foi um teste que executou cada cenário 10.000.000 de vezes. :-)

A cooperação é 0 + "123"

Fundição é (integer)"123"

Eu acho que Co-ercion é um pouco mais rápido. Ah, e tentar 0 + array('123')é um erro fatal no PHP. Você pode querer que seu código verifique o tipo do valor fornecido.

Meu código de teste está abaixo.


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";
        }
    }
}

Eu adicionei settypea este teste e o executei usando o PHP 7. O elenco saiu um pouco à frente e uma grande melhoria de desempenho em todos: string coerce: 1.9255340099335 string cast: 1.5142338275909 string settype: 4.149735212326 string fail coerce: 1.2346560955048 string fail cast: 1.3967711925507 string fail settype: 4.149735212326
bstoney

9

Você pode simplesmente converter uma string longa em um número inteiro usando FLOAT

$float = (float)$num;

Ou, se você quiser um número inteiro não flutuante, vá com

$float = (int)$num;

Por ex.

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

1
Hã? Se você quer um int, por que você não usaria (int)? Pode ser verdade que, se a cadeia de caracteres contiver um número inteiro, isso (float)retornará um valor que funciona muito como um número inteiro (mesmo que seu tipo interno seja provavelmente float), mas por que você faria isso, se a especificação retornasse um valor inteiro ? Suponha que a string recebida seja "1,3"? Você não receberá um número inteiro. Além disso, para quem lê o código no futuro, você deve dizer o que quer dizer. Se você quer dizer "deve ser um número inteiro", diga (int)não (float).
Home

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

3
Acredito que alguma referência ou prova esteja em ordem!
Mehran

$ int seria realmente um booleano aqui, se a instrução funcionasse, mas não seria, já que o primeiro parâmetro de settype () é passado por referência e, portanto, deve ser uma var.
Fila

7

excrato inteiro de qualquer string

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

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

// $ out = '1231233';


Você é o melhor dos melhores dos melhores! Passei horas convertendo algum var da string de dados json para inteiro, apenas seu método ajudou! obrigado!
Kamnibula

4

Mais resultados de benchmark ad-hoc:

$ 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

Seria melhor escrever a instrução sendo testada 10x em cada loop, para que o tempo não seja dominado pela sobrecarga do loop. Por exemplo { $i = +"-11"; $i = +"-11"; $i= +"-11"; $i= +"-11"; ... }. Também é arriscado usar o valor literal "-11"diretamente, a menos que você tenha certeza de que o idioma não fará parte do trabalho em tempo de compilação. Provavelmente está bem para uma linguagem dinâmica como PHP, mas mencionei para referência futura se estiver testando fórmulas em outras linguagens. Mais seguro definir uma variável $x = "-11"antes do loop de teste e usá-la. De modo que o código interno é $i =+$x.
Home

4

Executou um benchmark e a maneira mais rápida de obter um número inteiro real (usando todos os métodos disponíveis) é

$foo = (int)+"12.345";

Apenas usando

$foo = +"12.345";

retorna um flutuador.


2
Isso é mais rápido do que simplesmente (int)"12.345"? Mais rápido em que porcentagem?
Home
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.