PHP dize tamsayı dönüştürmek için en hızlı yolu


251

PHP kullanarak, böyle bir dizeyi "123"tamsayıya dönüştürmenin en hızlı yolu nedir?

Neden bu özel yöntem en hızlı? "hello"Veya bir dizi gibi beklenmedik girdiler alırsa ne olur ?


12
incinmezse (okunabilirlik), neden işleri mümkün olan en verimli şekilde yapmıyorsunuz?
nickf

19
Hıza zarar vermezse, neden işleri en okunaklı şekilde yapmıyorsunuz?
Andy Lester

4
@Andy, aşağıdaki karşılaştırmalı değerlendirme testlerine bakın. Arasındaki fark (int)ve intval()% 400 üzerinde olabilir!
nickf

6
en hızlı, çünkü kullanıcı deneyimi için hız önemlidir. Çok fazla işleminiz olduğunda, bunların HIZLI olmasını istersiniz!
philipp

13
Ölü bir atı vurmadan, hızın okunabilirliğe karşı sorusunun bu durumda ilgisiz olduğunu da söyleyebilirim, çünkü soru optimizasyon altında etiketlendi. Optimizasyon altında etiketlenmiş bir soruda hız istemenin nedeni açıklayıcıdır.
totallyNotLizards

Yanıtlar:


371

Kısa bir kıyaslama alıştırması yaptım:

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

Ortalama olarak, intval () çağrısı iki buçuk kat daha yavaştır ve girdiniz zaten bir tamsayı ise fark en büyüktür.

Neden olsa bilmek istiyorum .


Güncelleme: Testleri tekrar yapıyorum, bu sefer baskı ile (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   |
|-----------------|------------|-----------|-----------|

Zeyilname: Bu yöntemlerden birini seçerken bilmeniz gereken biraz beklenmedik bir davranışla karşılaştım:

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

PHP 5.3.1 kullanılarak test edilmiştir


9
Muhtemelen, intval () işlevinin bir işlev çağrısını çağırmasıyla, döküm doğrudan çevirmenin ifade hesaplayıcısında ele alınırken bir ilgisi vardır. Bu, bir işbirliğinin daha da hızlı olmasının nedeni olabilir.
staticsan

10
Baskı örneğiniz, php'nin az bilinen tekli artı operatörü kullanılarak daha da basitleştirilebilir. $ x + 0 -> + $ x
Ozzy

@Ozzy Bu harika. Bahşiş için teşekkürler! +"15" == 15
caiosm1005

1
O ilk kodda sadece iki vaka test eder beri @John (int)ve intvalve her çiftinde, bir% verir intval, baz harf olmalıdır (int). Ancak, özellikle daha sonra üçüncü bir dava eklediğinden bu kadar açık bir şekilde söylemiş olmanın daha net olacağı konusunda iyi bir fikriniz var!
ToolmakerSteve

2
Bu sonuçlarda daha yeni PHP sürümlerinde herhangi bir değişiklik var mı?
Artyom

34

Şahsen dökümün en güzel olduğunu hissediyorum.

$iSomeVar = (int) $sSomeOtherVar;

'Merhaba' gibi bir dize gönderilirse, tamsayı 0'a dönüştürülür. '22 yaşında 'gibi bir dize için tamsayı 22'ye dönüştürülür. Bir sayıya ayrıştırılamayan her şey 0 olur.

Gerçekten hıza İHTİYACINIZ varsa, sanırım buradaki diğer öneriler zorlamanın en hızlı olduğunu varsayarken doğrudur.


7
ilginç bir şekilde, diziler 1. 1 rakam alınıyor.
nickf

2
@nickf Öyle değil - 0'a da yayınlanabilir. Boole (true | false) değerini bir tam sayıya çevirir - 'false' = 0, 'true' = 1. Bir dizi% 100 boşsa yanlıştır ve sadece boş olsa bile HERHANGİ veri içeriyorsa doğrudur dizeleri veya NULL değerleri. Boş bir diziyi tamsayıya
Super Cat

15

Bir test yapın.

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

Bu, her senaryoyu 10.000.000 kez çalıştıran bir testti. :-)

Ortak eris 0 + "123"

Döküm (integer)"123"

Bence Co-ercion biraz daha hızlı. Oh, ve denemek 0 + array('123')PHP'de ölümcül bir hatadır. Kodunuzun sağlanan değerin türünü kontrol etmesini isteyebilirsiniz.

Test kodum aşağıda.


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

settypeBu teste ekledim ve PHP 7 kullanarak çalıştırdım. Cast biraz önde çıktı ve hepsine büyük bir performans artışı: string coerce: 1.9255340099335 string cast: 1.5142338275909 string settype: 4.149735212326 string fail coerce: 1.2346560955048 string fail cast: 1.3967711925507 string fail set
türü

9

FLOAT kullanarak uzun dizeyi tamsayıya dönüştürebilirsiniz

$float = (float)$num;

Veya tamsayı val kayan istemiyorsanız

$float = (int)$num;

Örn.

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

1
Ha? Bir int istiyorsanız, neden kullanmıyorsunuz (int)? Dize bir tamsayı içeriyorsa, bunun tamsayı (float)gibi çok fazla davranan bir değer döndüreceği doğru olabilir (iç türü büyük olasılıkla olsa da float), ancak belirtim bir tamsayı değeri döndürmek için bunu neden yapmalısınız? ? Gelen dize "1.3" olduğunu varsayalım? Bir tamsayı elde edemezsiniz. Ayrıca, gelecekte kodu okuyan herkes uğruna ne demek istediğinizi söylemelisiniz. "Bir tamsayı olmalı" demek istiyorsanız (int), değil deyin (float).
ToolmakerSteve

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

3
Bazı referansların veya kanıtların sırayla olduğuna inanıyorum!
Mehran

$ int, eğer deyim işe yaradıysa, burada bir boolean olur, ancak settype () 'in ilk parametresi referans tarafından geçildiğinden beri olmaz ve bu nedenle bir var olmalıdır.
Sıra

7

herhangi bir dizeden tamsayı hariç tutma

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

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

// $ out = '1231233';


Sen en iyinin en iyisisin! Ben json veri dizesinden tamsayı bazı var dönüştürmek için saat geçirdim, sadece yöntem yardımcı oldu! teşekkür ederim!
Kamnibula

4

Diğer geçici karşılaştırma sonuçları:

$ 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

Test edilen ifadeyi her döngüde 10x yazmak daha iyi olur, böylece zamana döngü yükü hakim olmaz. Örn { $i = +"-11"; $i = +"-11"; $i= +"-11"; $i= +"-11"; ... }. "-11"Dilin derleme zamanında işin bir kısmını yapmayacağından emin değilseniz, gerçek değeri doğrudan kullanmak da risklidir . Muhtemelen PHP gibi dinamik bir dil için tamam, ancak diğer dillerde formülleri test ediyorsanız gelecekteki referans için bahsedeceğim. $x = "-11"Test döngüsünden önce bir değişken ayarlamak ve daha sonra kullanmak için daha güvenlidir. Böylece iç kod $i =+$x.
ToolmakerSteve

4

Bir kıyaslama koştu ve gerçek bir tamsayı elde etmenin en hızlı yolu çıkıyor (mevcut tüm yöntemleri kullanarak)

$foo = (int)+"12.345";

Sadece

$foo = +"12.345";

bir şamandıra döndürür.


2
Bu basit olandan daha (int)"12.345"mı hızlı ? Yüzde kadar daha hızlı?
ToolmakerSteve
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.