Il modo più veloce per convertire la stringa in intero in PHP


251

Usando PHP, qual è il modo più veloce per convertire una stringa come questa: "123"in un numero intero?

Perché quel particolare metodo è il più veloce? Cosa succede se riceve input imprevisti, come "hello"o un array?


12
bene se non fa male (leggibilità), perché non fare le cose nel modo più efficiente possibile?
nickf

19
Se non danneggia la velocità, perché non fare le cose nel modo più leggibile possibile?
Andy Lester,

4
@Andy, guarda i test benchmark qui sotto. La differenza tra (int)e intval()può essere superiore al 400%!
nickf

6
il più veloce è importante perché la velocità è importante per l'esperienza dell'utente. Quando hai molte operazioni in corso, vuoi averle VELOCEMENTE!
philipp

13
senza calciare un cavallo morto, direi anche che la questione della velocità contro la leggibilità è irrilevante in questo caso, perché la domanda è stata etichettata come ottimizzazione. La ragione per volere la velocità in una domanda etichettata come ottimizzazione è autoesplicativa.
totallyNotLizards il

Risposte:


371

Ho appena avviato un rapido esercizio di 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%)

In media, chiamare intval () è due volte e mezzo più lento e la differenza è maggiore se il tuo input è già un numero intero.

Sarei interessato a sapere perché .


Aggiornamento: ho eseguito di nuovo i test, questa volta con la coercizione (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   |
|-----------------|------------|-----------|-----------|

Addendum: ho appena riscontrato un comportamento leggermente inaspettato di cui dovresti essere consapevole quando scegli uno di questi metodi:

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

Testato con PHP 5.3.1


9
Probabilmente ha qualcosa a che fare con il fatto che intval () invoca una chiamata di funzione, mentre il cast viene gestito direttamente nel calcolatore di espressioni dell'interprete. Questo potrebbe anche essere il motivo per cui una coercizione è ancora più veloce.
staticsan

10
Il tuo esempio di coercizione può essere ulteriormente semplificato utilizzando l'operatore unario plus poco conosciuto di php. $ x + 0 -> + $ x
Ozzy

@Ozzy È fantastico. Grazie per il consiglio! +"15" == 15
caiosm1005,

1
@John poiché prova solo due casi in quel primo codice (int)e intval, e in ogni coppia, dà un% su intval, il caso base deve essere (int). Ma hai un buon punto sul fatto che sarebbe stato più chiaro se lo avesse detto in modo esplicito, soprattutto da quando in seguito ha aggiunto un terzo caso!
ToolmakerSteve

2
Sono state apportate modifiche a questi risultati nelle versioni più recenti di PHP?
Artyom,

34

Personalmente ritengo che il casting sia il più bello.

$iSomeVar = (int) $sSomeOtherVar;

Se viene inviata una stringa come 'Hello', verrà lanciata su un numero intero 0. Per una stringa come '22 anni ', verrà lanciata su un numero intero 22. Tutto ciò che non può analizzare su un numero diventa 0.

Se davvero AVETE BISOGNO della velocità, immagino che gli altri suggerimenti qui siano corretti nel presupporre che la coercizione sia la più veloce.


7
è interessante notare che le matrici vengono lanciate su 1. vai a figura.
nickf,

2
@nickf Non è così - Può essere lanciato anche su 0. Lancia il suo valore booleano (true | false) a un numero intero - 'false' = 0, 'true' = 1. Un array è falso se è vuoto al 100% ed è vero se contiene QUALSIASI dato, anche se è solo vuoto stringhe o valori NULL. Se dovessi trasmettere un array vuoto a un numero intero, diventerebbe 0. (Sì, lo so questo vecchio!)
Super Cat,

15

Esegui un test.

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

Questo è stato un test che ha eseguito ogni scenario 10.000.000 di volte. :-)

La coercizione è 0 + "123"

Casting è (integer)"123"

Penso che Co-ercion sia un po 'più veloce. Oh, e provare 0 + array('123')è un errore fatale in PHP. È possibile che il codice controlli il tipo di valore fornito.

Il mio codice di prova è sotto.


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

Ho aggiunto settypequesto test e l'ho eseguito usando PHP 7. Il cast è uscito leggermente davanti e un grande miglioramento delle prestazioni su tutti: stringa coerce: 1.9255340099335 stringa cast: 1.5142338275909 stringa tipo: 4.149735212326 stringa non riuscita coerce: 1.2346560955048 stringa non riuscita cast: 1.3967711925507 stringa non riuscita settype: 4.149735212326
bstoney,

9

Puoi semplicemente convertire una stringa lunga in un numero intero usando FLOAT

$float = (float)$num;

Oppure, se vuoi che l'intero non sia mobile, procedi con

$float = (int)$num;

Per es.

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

1
Eh? Se vuoi un int, perché non dovresti usare (int)? Può essere vero che se la stringa contiene un numero intero, ciò (float)restituirà un valore che agisce in modo molto simile a un numero intero (anche se il suo tipo interno è probabilmente float), ma perché dovresti farlo, se la specifica deve restituire un valore intero ? Supponiamo che la stringa in arrivo sia "1.3"? Non otterrai un numero intero. Inoltre, per chiunque legga il codice in futuro, dovresti dire cosa intendi. Se vuoi dire "dovrebbe essere un numero intero", allora dì di (int)no (float).
ToolmakerSteve

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

3
Credo che qualche riferimento o prova sia in ordine!
Mehran,

$ int sarebbe effettivamente un valore booleano qui, se l'istruzione funzionasse, ma non lo sarebbe poiché il primo parametro di settype () viene passato per riferimento e quindi deve essere un var.
Coda

7

intero viene espulso da qualsiasi stringa

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

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

// $ out = '1231233';


Sei il meglio del meglio del meglio! Ho passato ore a convertire alcuni var dalla stringa di dati json in numeri interi, solo il tuo metodo ha aiutato! grazie!
Kamnibula,

4

Altri risultati di 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

Sarebbe meglio scrivere l'istruzione testata 10 volte in ciascun loop, in modo che il tempo non sia dominato dal sovraccarico del loop. Es { $i = +"-11"; $i = +"-11"; $i= +"-11"; $i= +"-11"; ... }. È anche rischioso utilizzare "-11"direttamente il valore letterale , a meno che non si sia certi che la lingua non eseguirà parte del lavoro in fase di compilazione. Probabilmente OK per un linguaggio dinamico come PHP, ma menziono per riferimento futuro se collaudo formule in altre lingue. È più sicuro impostare una variabile $x = "-11"prima del ciclo di prova, quindi utilizzarla. In modo che il codice interno sia $i =+$x.
ToolmakerSteve

4

Ha eseguito un benchmark e si scopre che il modo più veloce per ottenere un numero intero reale (usando tutti i metodi disponibili) è

$foo = (int)+"12.345";

Sto solo usando

$foo = +"12.345";

restituisce un float.


2
Questo è più veloce del semplice (int)"12.345"? Più veloce di quale percentuale?
ToolmakerSteve
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.