Самый быстрый способ преобразовать строку в целое число в PHP

251

С помощью PHP, какой самый быстрый способ преобразовать строку как это: "123"целое число?

Почему этот конкретный метод самый быстрый? Что произойдет, если он получит неожиданный ввод, например, "hello"или массив?

nickf
источник
12
хорошо, если это не повредит (удобочитаемость), почему бы не сделать вещи наиболее эффективным способом?
Nickf
19
Если это не повредит скорости, почему бы не сделать вещи максимально читабельным способом?
Энди Лестер
4
@ Энди, посмотри тесты ниже. Разница между (int)и intval()может быть более 400%!
Ник
6
самое быстрое имеет значение, потому что скорость имеет значение для пользовательского опыта. Когда у вас много операций, вы хотите, чтобы они выполнялись БЫСТРО!
Филипп
13
не пинайте мертвую лошадь, я бы также сказал, что вопрос скорости и читабельности в данном случае не имеет значения, поскольку этот вопрос был помечен при оптимизации. Причина стремления к скорости в вопросе, помеченном при оптимизации, очевидна.
totallyNotLizards

Ответы:

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

nickf
источник
9
Вероятно, это связано с тем, что intval () вызывает вызов функции, в то время как приведение обрабатывается непосредственно в калькуляторе выражений интерпретатора. Это также может быть причиной того, что коэрция еще быстрее.
staticsan
10
Ваш пример приведения может быть еще более упрощен с помощью малоизвестного унарного оператора плюс в php. $ x + 0 -> + $ x
Оззи
@ Оззи Это круто. Спасибо за чаевые! +"15" == 15
caiosm1005
1
@ Джон, так как он тестирует только два случая в этом первом коде, (int)и intval, и в каждой паре, дает% on intval, базовый случай должен быть (int). Но у вас есть хорошее замечание, что было бы яснее, если бы он сказал об этом прямо, тем более что позже он добавил третий случай!
ToolmakerSteve
2
Есть ли какие-либо изменения в этом результате в новых версиях PHP?
Артём
34

Я лично чувствую, что кастинг - самый красивый.

$iSomeVar = (int) $sSomeOtherVar;

Если будет отправлена ​​строка типа «Hello», она будет приведена к целому числу 0. Для строки, такой как «22 лет», она будет приведена к целому числу 22. Все, что она не может проанализировать, становится 0.

Если вам действительно нужна скорость, я думаю, что другие предложения здесь верны, если предположить, что принуждение является самым быстрым.

Rexxars
источник
7
Интересно, что массивы приводятся к 1. go figure.
Nickf
2
@nickf Не так - он также может быть приведен к 0. Он преобразует свое логическое (true | false) значение в целое число - «false» = 0, «true» = 1. Массив равен false, если он на 100% пуст, и имеет значение true, если он содержит ЛЮБЫЕ данные, даже если он просто пуст строки или значения NULL. Если вы приведете пустой массив к целому числу, оно станет 0. (Да, я знаю это старое!)
Super Cat
15

Запустите тест.

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

Это был тест, который запускал каждый сценарий 10 000 000 раз. :-)

Коэрция это 0 + "123"

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

Я думаю, что Co-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";
        }
    }
}
staticsan
источник
Я добавил settypeк этому тесту и запустил его, используя PHP 7. Преобразование получилось немного впереди, и значительно улучшилось быстродействие по всем параметрам: string coerce: 1.9255340099335 приведение строки: 1.5142338275909 string settype: 4.149735212326 строка сбой coerce: 1.2346560955048 сбой строки: 1.3967711925507 сбой строки settype: 4.149735212326
bstoney
9

Вы можете просто конвертировать длинную строку в целое, используя FLOAT

$float = (float)$num;

Или, если вы хотите, чтобы целое число не плавающее val, тогда перейдите

$float = (int)$num;

Например

(int)   "1212.3"   = 1212 
(float) "1212.3"   = 1212.3
Нищит Дханани
источник
1
А? Если вы хотите int, почему бы вам не использовать (int)? Может быть верно, что если строка содержит целое число, это (float)вернет значение, которое во многом похоже на целое число (даже если его внутренний тип, вероятно, является float), но зачем вам это делать, если спецификация должна возвращать целочисленное значение ? Предположим, что входящая строка "1,3"? Вы не получите целое число. Кроме того, ради того, чтобы кто-нибудь читал код в будущем, вы должны сказать, что вы имеете в виду. Если вы имеете в виду «это должно быть целое число», то говорите (int), что нет (float).
ToolmakerSteve
7
$int = settype("100", "integer"); //convert the numeric string to int
Элрик Вамугу
источник
3
Я считаю, что некоторые ссылки или доказательства в порядке!
Мехран
$ int на самом деле здесь будет логическим, если оператор сработает, но это не так, поскольку первый параметр settype () передается по ссылке и поэтому должен быть переменной var.
Очередь
7

целое число извлекается из любой строки

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

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

// $ out = '1231233';

разработчик
источник
Ты лучший из лучших из лучших! Я потратил часы, чтобы преобразовать некоторую переменную из строки данных 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
Даниил
источник
Было бы лучше написать проверяемый оператор 10x в каждом цикле, чтобы время не зависело от затрат на цикл. Например { $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