Найшвидший спосіб перетворення рядка в ціле число в PHP


251

Використовуючи PHP, який найшвидший спосіб перетворити такий рядок: "123"у ціле число?

Чому саме цей метод є найшвидшим? Що станеться, якщо він отримає несподіваний вхід, наприклад, "hello"або масив?


12
добре, якщо це не зашкодить (читабельність), чому б не зробити речі найбільш ефективним способом?
nickf

19
Якщо це не заважає швидкості, чому б не зробити речі найбільш читабельним способом?
Енді Лестер

4
@Andy, подивіться тести на еталони нижче. Різниця між (int)і intval()може перевищувати 400%!
nickf

6
найшвидші питання, оскільки швидкість має значення для досвіду користувача. Коли у вас триває багато операцій, ви хочете зробити їх ШВИДКО!
Філіпп

13
не відштовхуючи мертвого коня, я б також сказав, що питання швидкості проти читабельності в цьому випадку не має значення, оскільки це питання було позначене оптимізацією. Причина бажати швидкості у запитанні, позначеному оптимізацією, - це сама пояснення.
totalNotLizards

Відповіді:


371

Я щойно налаштував швидку контрольну роботу:

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

У середньому виклик intval () у два з половиною рази повільніше, і різниця найбільша, якщо ваш вхід вже є цілим числом.

Мені було б цікаво дізнатися, чому все-таки.


Оновлення: я знову запустив тести, на цей раз з примусом (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   |
|-----------------|------------|-----------|-----------|

Додаток: Я щойно стикався з трохи несподіваною поведінкою, яку слід пам’ятати, обираючи один із цих методів:

$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


9
Це, мабуть, щось пов'язане з тим, що intval () викликає функцію виклику, в той час як кастинг обробляється безпосередньо в калькуляторі виразів інтерпретатора. Це також може бути причиною того, що співпраця ще швидше.
статик

10
Ваш приклад примусу можна додатково спростити, використовуючи маловідомий оператор php unry plus, відомий php. $ x + 0 -> + $ x
Ozzy

@Ozzy Це приголомшливо. Дякую за пораду! +"15" == 15
caiosm1005

1
@John, оскільки він перевіряє лише два випадки в цьому першому коді, (int)і intval, і в кожній парі, дає% на intval, базовий регістр повинен бути (int). Але у вас є хороша думка, що було б зрозуміліше, якби він сказав це прямо, тим більше, що згодом додав третій випадок!
ToolmakerSteve

2
Чи є якісь зміни цього результату в нових версіях PHP?
Артем

34

Я особисто відчуваю, що кастинг - найкрасивіший.

$iSomeVar = (int) $sSomeOtherVar;

Якщо буде надісланий рядок типу "Привіт", він буде переданий на ціле число 0. Для рядка, такого як "22 роки", він буде переданий на ціле число 22. Все, що він не може розібрати на число, стає 0.

Якщо вам дійсно НЕОБХІДНА швидкість, я думаю, що інші пропозиції тут є правильними, припускаючи, що примус є найшвидшим.


7
Цікаво, що масиви отримують літ до 1. go figure.
nickf

2
@nickf Не так - Це може бути додано до 0. Він передає це булеве (справжнє | хибне) значення на ціле число - 'false' = 0, 'true' = 1. Масив хибний, якщо він на 100% порожній, і це правда, якщо він містить будь-які дані, навіть якщо він просто порожній рядки або значення NULL. Якби ви вивели порожній масив до цілого числа, він би став 0. (Так, я знаю це старе!)
Super Cat

15

Проведіть тест.

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

Це був тест, який проходив кожен сценарій 1000000000 разів. :-)

Ко-ercion є 0 + "123"

Кастинг є (integer)"123"

Я думаю, що ко-ercion є крихітним трохи швидше. О, і спроба 0 + array('123')є фатальною помилкою в PHP. Можливо, ви хочете, щоб ваш код перевіряв тип наданого значення.

Мій тестовий код нижче.


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

Я додав settypeдо цього тесту і запустив його за допомогою PHP 7. Cast вийшов трохи попереду, і велике поліпшення продуктивності у всіх: рядок примусу: 1.9255340099335 кидок рядка: 1.5142338275909 Набір рядків: 4.149735212326 string fail coerce: 1.2346560955048 string fail cast: 1.3967711925507 string fail cast: 1.3967711925507 string fail поселення: 4.149735212326
bstoney

9

Ви можете просто перетворити довгий рядок у ціле число за допомогою FLOAT

$float = (float)$num;

Або якщо ви хочете, щоб ціле число не плавало val, тоді перейдіть з

$float = (int)$num;

Для екс.

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

1
Так? Якщо ви хочете інт, чому б вам не скористатися (int)? Це може бути правдою, що якщо рядок містить ціле число, воно (float)поверне значення, яке дуже схоже на ціле число (навіть якщо його внутрішній тип, ймовірно float), але навіщо це робити, якщо специфікація повертає ціле число ? Припустимо, вхідний рядок дорівнює "1,3"? Ви не отримаєте ціле число. Також заради того, щоб хтось читав код у майбутньому, вам слід сказати, що ви маєте на увазі. Якщо ви маєте на увазі "це повинно бути ціле число", то скажіть (int), що ні (float).
ToolmakerSteve

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

3
Я вірю, що посилання чи доказ є в порядку!
Мехран

$ int насправді був би булевим, якби оператор працював, але це не так, оскільки перший параметр resype () передається за посиланням, і тому він повинен бути var.
Черга

7

ціле вилучення з будь-якого рядка

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

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

// $ out = '1231233';


Ти найкращий з найкращих з найкращих! Я витратив години, щоб перетворити деякий var з рядка даних json в цілий, тільки ваш метод допоміг! спасибі!
Камнібула

4

Більше спеціальних результатів:

$ 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

Було б краще написати твердження, яке тестується 10 разів у кожному циклі, щоб час не переважав над головою циклу. Напр { $i = +"-11"; $i = +"-11"; $i= +"-11"; $i= +"-11"; ... }. Також ризиковано "-11"безпосередньо використовувати буквальне значення , якщо ви не впевнені, що мова не виконає якусь роботу під час компіляції. Можливо, добре для такої динамічної мови, як PHP, але я згадаю для подальшої довідки, якщо тестувати формули на інших мовах. Безпечніше встановити змінну $x = "-11"перед циклом тестування, а потім використовувати її. Так що внутрішній код є $i =+$x.
ToolmakerSteve

4

Виставив тест, і виявляється, найшвидший спосіб отримати дійсне ціле число (використовуючи всі доступні методи)

$foo = (int)+"12.345";

Просто за допомогою

$foo = +"12.345";

повертає поплавок.


2
Це швидше, ніж просто (int)"12.345"? Швидше на який відсоток?
ToolmakerSteve
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.