Cara tercepat untuk mengonversi string menjadi integer di PHP

251

Menggunakan PHP, apa cara tercepat untuk mengonversi string seperti ini: "123"ke integer?

Mengapa metode khusus itu paling cepat? Apa yang terjadi jika mendapat input yang tidak terduga, seperti "hello"atau array?

nickf
sumber
12
baik jika tidak sakit (mudah dibaca), mengapa tidak melakukan hal-hal dengan cara yang seefisien mungkin?
nickf
19
Jika tidak melukai kecepatan, mengapa tidak melakukan hal-hal dengan cara yang paling mudah dibaca?
Andy Lester
4
@Andy, lihat tes benchmark di bawah ini. Perbedaan antara (int)dan intval()bisa lebih dari 400%!
nickf
6
hal tercepat karena kecepatan penting untuk pengalaman pengguna. Ketika Anda memiliki banyak operasi yang sedang berlangsung, Anda ingin memilikinya CEPAT!
philipp
13
tanpa menendang kuda mati, saya juga akan mengatakan bahwa pertanyaan tentang kecepatan vs keterbacaan tidak relevan dalam kasus ini, karena pertanyaan itu ditandai di bawah optimasi. Alasan menginginkan kecepatan dalam pertanyaan yang ditandai dalam pengoptimalan cukup jelas.
totallyNotLizards

Jawaban:

371

Saya baru saja membuat latihan pembandingan cepat:

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

Rata-rata, panggilan intval () dua setengah kali lebih lambat, dan perbedaannya adalah yang terbesar jika input Anda sudah bilangan bulat.

Saya tertarik untuk tahu mengapa .


Pembaruan: Saya sudah menjalankan tes lagi, kali ini dengan paksaan (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   |
|-----------------|------------|-----------|-----------|

Tambahan: Saya baru saja menemukan perilaku yang sedikit tidak terduga yang harus Anda perhatikan ketika memilih salah satu dari metode ini:

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

Diuji menggunakan PHP 5.3.1

nickf
sumber
9
Mungkin ada hubungannya dengan fakta bahwa intval () memanggil pemanggilan fungsi, sementara para pemain ditangani langsung dalam kalkulator ekspresi penerjemah. Ini mungkin juga menjadi alasan koersi bahkan lebih cepat.
Statika
10
Contoh paksaan Anda dapat lebih disederhanakan dengan menggunakan operator unary plus php yang sedikit diketahui. $ x + 0 -> + $ x
Ozzy
@Ozzy Itu luar biasa. Terima kasih atas tipnya! +"15" == 15
caiosm1005
1
@ John karena ia menguji hanya dua case dalam kode pertama itu, (int)dan intval, dan pada masing-masing pasangan, memberikan% on intval, case dasar harus (int). Tetapi Anda memiliki poin yang bagus bahwa akan lebih jelas jika dia mengatakannya secara eksplisit, terutama karena ia kemudian menambahkan kasus ketiga!
ToolmakerSteve
2
Apakah ada perubahan pada hasil ini dalam versi PHP yang lebih baru?
Artyom
34

Saya pribadi merasa casting adalah yang tercantik.

$iSomeVar = (int) $sSomeOtherVar;

Jika string seperti 'Hello' dikirim, itu akan dilemparkan ke integer 0. Untuk string seperti '22 tahun ', itu akan dilemparkan ke integer 22. Apa pun yang tidak dapat diuraikan ke angka menjadi 0.

Jika Anda benar-benar MEMBUTUHKAN kecepatan, saya kira saran lain di sini benar dalam mengasumsikan bahwa pemaksaan adalah yang tercepat.

Rexxars
sumber
7
Menariknya, array di-cast menjadi 1. go figure.
nickf
2
@nickf Tidak begitu - Ini dapat dilemparkan ke 0 juga. Ini melemparkan nilai boolean (true | false) ke integer - 'false' = 0, 'true' = 1. Array salah jika 100% kosong, dan memang benar jika berisi data APAPUN, bahkan jika itu hanya kosong nilai string atau NULL. Jika Anda melemparkan array kosong ke integer, itu akan menjadi 0. (Ya, saya tahu ini lama!)
Super Cat
15

Jalankan tes.

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

Ini adalah tes yang menjalankan setiap skenario 10.000.000 kali. :-)

Koersi adalah 0 + "123"

Casting adalah (integer)"123"

Saya pikir Co-ercion sedikit lebih cepat. Oh, dan mencoba 0 + array('123')adalah kesalahan fatal dalam PHP. Anda mungkin ingin kode Anda memeriksa jenis nilai yang disediakan.

Kode pengujian saya di bawah.


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";
        }
    }
}
ahli statika
sumber
Saya menambahkan settypeke tes ini dan menjalankannya menggunakan PHP 7. Cast keluar sedikit di depan dan peningkatan kinerja besar atas semua: string coerce: 1.9255340099335 string pemain: 1.5142338275909 string settype: 4.149735212326 string fail coerce: 1.2346560955048 string fail cast: 1.3967711925507 gagal settype: 4.149735212326
bstoney
9

Anda bisa mengubah string panjang menjadi integer dengan menggunakan FLOAT

$float = (float)$num;

Atau jika Anda ingin integer tidak mengambang val kemudian pergi bersama

$float = (int)$num;

Misalnya

(int)   "1212.3"   = 1212 
(float) "1212.3"   = 1212.3
Nishchit Dhanani
sumber
1
Hah? Jika Anda menginginkan int, mengapa Anda tidak menggunakannya (int)? Mungkin benar bahwa jika string berisi bilangan bulat, itu (float)akan mengembalikan nilai yang banyak bertindak seperti bilangan bulat (meskipun jenis internalnya mungkin float), tetapi mengapa Anda melakukan ini, jika spesifikasinya adalah mengembalikan nilai integer ? Misalkan string yang masuk adalah "1.3"? Anda tidak akan mendapatkan bilangan bulat. Juga, demi siapa pun yang membaca kode di masa mendatang, Anda harus mengatakan apa yang Anda maksud. Jika Anda maksudkan "itu harus bilangan bulat", maka katakan (int), tidak (float).
ToolmakerSteve
7
$int = settype("100", "integer"); //convert the numeric string to int
Elric Wamugu
sumber
3
Saya percaya beberapa referensi atau bukti sudah beres!
Mehran
$ int akan benar-benar menjadi boolean di sini, jika pernyataan itu berfungsi, tetapi itu tidak akan terjadi sejak parameter pertama dari settype () dilewatkan oleh referensi dan karenanya harus berupa var.
Antrian
7

integer excract dari sembarang string

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

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

// $ out = '1231233';

Pengembang
sumber
Anda adalah yang terbaik dari yang terbaik dari yang terbaik! Saya telah menghabiskan berjam-jam untuk mengkonversi beberapa var dari json data string ke integer, hanya metode Anda yang membantu! Terima kasih!
Kamnibula
4

Lebih banyak hasil 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
Daniel
sumber
Akan lebih baik untuk menulis pernyataan yang sedang diuji 10x di setiap loop, sehingga waktu tidak didominasi oleh overhead loop. Misalnya { $i = +"-11"; $i = +"-11"; $i= +"-11"; $i= +"-11"; ... }. Juga berisiko menggunakan nilai literal "-11"secara langsung, kecuali jika Anda yakin bahasanya tidak akan melakukan beberapa pekerjaan pada waktu kompilasi. Mungkin OK untuk bahasa dinamis seperti PHP, tetapi saya menyebutkan untuk referensi di masa depan jika menguji rumus dalam bahasa lain. Lebih aman untuk mengatur variabel $x = "-11"sebelum loop tes, dan kemudian menggunakannya. Sehingga kode bagian dalamnya $i =+$x.
ToolmakerSteve
4

Berlari patokan, dan ternyata cara tercepat untuk mendapatkan bilangan bulat nyata (menggunakan semua metode yang tersedia) adalah

$foo = (int)+"12.345";

Hanya menggunakan

$foo = +"12.345";

mengembalikan pelampung.

Andrew Plank
sumber
2
Ini lebih cepat dari sekadar (int)"12.345"? Lebih cepat berapa persen?
ToolmakerSteve