Der schnellste Weg, um Zeichenfolgen in PHP in Ganzzahlen umzuwandeln

251

Was ist mit PHP der schnellste Weg, einen String wie diesen "123"in eine Ganzzahl umzuwandeln ?

Warum ist diese Methode die schnellste? Was passiert, wenn unerwartete Eingaben wie z. B. "hello"ein Array eingehen?

nickf
quelle
12
Nun, wenn es nicht weh tut (Lesbarkeit), warum nicht die Dinge so effizient wie möglich machen?
Nickf
19
Wenn es die Geschwindigkeit nicht beeinträchtigt, warum nicht die Dinge so gut wie möglich machen?
Andy Lester
4
@Andy, sieh dir die folgenden Benchmark-Tests an. Der Unterschied zwischen (int)und intval()kann über 400% betragen!
Nickf
6
Schnellste sind wichtig, weil Geschwindigkeit für die Benutzererfahrung wichtig ist. Wenn Sie viele Operationen durchführen, möchten Sie sie SCHNELL haben!
Philipp
13
Ohne ein totes Pferd zu treten, würde ich auch sagen, dass die Frage nach Geschwindigkeit und Lesbarkeit in diesem Fall irrelevant ist, da die Frage unter Optimierung markiert wurde. Der Grund für den Wunsch nach Geschwindigkeit in einer unter Optimierung getaggten Frage ist selbsterklärend.
totalNotLizards

Antworten:

371

Ich habe gerade eine schnelle Benchmarking-Übung eingerichtet:

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

Im Durchschnitt ist der Aufruf von intval () zweieinhalb Mal langsamer, und der Unterschied ist am größten, wenn Ihre Eingabe bereits eine Ganzzahl ist.

Es würde mich interessieren, warum .


Update: Ich habe die Tests erneut durchgeführt, diesmal mit Zwang (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   |
|-----------------|------------|-----------|-----------|

Nachtrag: Ich bin gerade auf ein etwas unerwartetes Verhalten gestoßen, das Sie bei der Auswahl einer dieser Methoden beachten sollten:

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

Getestet mit PHP 5.3.1

nickf
quelle
9
Es hat wahrscheinlich etwas damit zu tun, dass intval () einen Funktionsaufruf aufruft, während die Umwandlung direkt im Ausdrucksrechner des Interpreters behandelt wird. Dies kann auch der Grund sein, warum eine Zusammenarbeit noch schneller ist.
Staticsan
10
Ihr Zwangsbeispiel kann durch die Verwendung des wenig bekannten unären Plus-Operators von php weiter vereinfacht werden. $ x + 0 -> + $ x
Ozzy
@ Ozzy Das ist großartig. Danke für den Tipp! +"15" == 15
caiosm1005
1
@ John , da er nur zwei Fälle , in diesem ersten Code prüft, (int)und intval, und in jedem Paar, gibt einen% auf intval, muss der Basisfall sein (int). Aber Sie haben einen guten Punkt, dass es klarer gewesen wäre, wenn er dies ausdrücklich gesagt hätte, zumal er später einen dritten Fall hinzugefügt hat!
ToolmakerSteve
2
Gibt es Änderungen an diesen Ergebnissen in neueren PHP-Versionen?
Artyom
34

Ich persönlich finde Casting am schönsten.

$iSomeVar = (int) $sSomeOtherVar;

Sollte eine Zeichenfolge wie 'Hallo' gesendet werden, wird sie in eine Ganzzahl 0 umgewandelt. Bei einer Zeichenfolge wie '22 Jahre alt 'wird sie in eine Ganzzahl 22 umgewandelt. Alles, was nicht auf eine Zahl analysiert werden kann, wird zu 0.

Wenn Sie wirklich die Geschwindigkeit brauchen, sind die anderen Vorschläge hier richtig, wenn Sie davon ausgehen, dass Zwang am schnellsten ist.

Rexxars
quelle
7
Interessanterweise werden Arrays auf 1 gesetzt.
Nickf
2
@nickf Nicht so - Es kann auch auf 0 gesetzt werden. Der boolesche Wert (true | false) wird in eine Ganzzahl umgewandelt - 'false' = 0, 'true' = 1. Ein Array ist false, wenn es zu 100% leer ist, und true, wenn es ALLE Daten enthält, auch wenn es nur leer ist Zeichenfolgen oder NULL-Werte. Wenn Sie ein leeres Array in eine Ganzzahl umwandeln würden, würde es 0 werden. (Ja, ich bin mir dessen bewusst!)
Super Cat
15

Führen Sie einen Test durch.

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

Dies war ein Test, bei dem jedes Szenario 10.000.000 Mal ausgeführt wurde. :-)

Co-ercion ist 0 + "123"

Casting ist (integer)"123"

Ich denke, Co-ercion ist ein kleines bisschen schneller. Oh, und es 0 + array('123')ist ein schwerwiegender Fehler in PHP. Möglicherweise möchten Sie, dass Ihr Code den Typ des angegebenen Werts überprüft.

Mein Testcode ist unten.


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";
        }
    }
}
staticsan
quelle
Ich settypehabe diesen Test hinzugefügt und ihn mit PHP 7 ausgeführt. Die Besetzung hat sich vorne leicht herausgestellt und insgesamt eine große Leistungsverbesserung erzielt: String-Koerce: 1.9255340099335 String-Cast: 1.5142338275909 String-Settype: 4.149735212326 String-Fail-Coerce: 1.2346560955048 String-Fail-Cast: 1.3967711925507 String Fail Cast Settype: 4.149735212326
Bstoney
9

Mit FLOAT können Sie lange Zeichenfolgen einfach in Ganzzahlen konvertieren

$float = (float)$num;

Oder wenn Sie möchten, dass eine Ganzzahl nicht schwebend ist, gehen Sie mit

$float = (int)$num;

Zum Beispiel.

(int)   "1212.3"   = 1212 
(float) "1212.3"   = 1212.3
Nishchit Dhanani
quelle
1
Huh? Wenn Sie ein int wollen, warum würden Sie nicht verwenden (int)? Es mag sein, dass, wenn die Zeichenfolge eine Ganzzahl enthält, (float)ein Wert zurückgegeben wird, der sich stark wie eine Ganzzahl verhält (obwohl der interne Typ wahrscheinlich ist float), aber warum sollten Sie dies tun, wenn die Spezifikation einen Ganzzahlwert zurückgeben soll ? Angenommen, die eingehende Zeichenfolge ist "1.3"? Sie erhalten keine Ganzzahl. Damit in Zukunft jeder den Code lesen kann, sollten Sie auch sagen, was Sie meinen. Wenn Sie "es sollte eine ganze Zahl sein" meinen (int), dann sagen Sie nicht (float).
ToolmakerSteve
7
$int = settype("100", "integer"); //convert the numeric string to int
Elric Wamugu
quelle
3
Ich glaube, ein Hinweis oder Beweis ist angebracht!
Mehran
$ int wäre hier tatsächlich ein Boolescher Wert, wenn die Anweisung funktionieren würde, aber dies wäre nicht der Fall, da der erste Parameter von settype () als Referenz übergeben wird und daher eine var sein muss.
Warteschlange
7

Ganzzahlauszug aus einer beliebigen Zeichenfolge

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

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

// $ out = '1231233';

Entwickler
quelle
Du bist der Beste der Besten der Besten! Ich habe Stunden damit verbracht, eine Variable von einer JSON-Datenzeichenfolge in eine Ganzzahl umzuwandeln. Nur Ihre Methode hat geholfen! Danke!
Kamnibula
4

Weitere Ad-hoc-Benchmark-Ergebnisse:

$ 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
quelle
Es ist besser, die zu testende Anweisung 10x in jede Schleife zu schreiben, damit die Zeit nicht vom Schleifen-Overhead dominiert wird. ZB { $i = +"-11"; $i = +"-11"; $i= +"-11"; $i= +"-11"; ... }. Es ist auch riskant, den wörtlichen Wert "-11"direkt zu verwenden, es sei denn, Sie sind sicher, dass die Sprache beim Kompilieren einen Teil der Arbeit nicht erledigt. Wahrscheinlich in Ordnung für eine dynamische Sprache wie PHP, aber ich erwähne sie zum späteren Nachschlagen, wenn ich Formeln in anderen Sprachen teste. Es ist sicherer, eine Variable $x = "-11"vor der Testschleife festzulegen und sie dann zu verwenden. Damit ist der innere Code $i =+$x.
ToolmakerSteve
4

Es wurde ein Benchmark erstellt, und es stellt sich heraus, dass der schnellste Weg, eine echte Ganzzahl zu erhalten (unter Verwendung aller verfügbaren Methoden), ist

$foo = (int)+"12.345";

Nur mit

$foo = +"12.345";

gibt einen float zurück.

Andrew Plank
quelle
2
Das ist schneller als einfach (int)"12.345"? Um wie viel Prozent schneller?
ToolmakerSteve