Cách nhanh nhất để chuyển đổi chuỗi thành số nguyên trong PHP


251

Sử dụng PHP, cách nhanh nhất để chuyển đổi một chuỗi như thế này: "123"thành một số nguyên là gì?

Tại sao phương pháp cụ thể đó là nhanh nhất? Điều gì xảy ra nếu nó nhận được đầu vào bất ngờ, chẳng hạn như "hello"hoặc một mảng?


12
tốt nếu nó không bị tổn thương (khả năng đọc), tại sao không làm mọi thứ theo cách hiệu quả nhất có thể?
nickf

19
Nếu nó không ảnh hưởng đến tốc độ, tại sao không làm mọi thứ theo cách dễ đọc nhất có thể?
Andy Lester

4
@Andy, hãy xem các bài kiểm tra điểm chuẩn dưới đây. Sự khác biệt giữa (int)intval()có thể hơn 400%!
nickf

6
vấn đề nhanh nhất vì tốc độ quan trọng đối với trải nghiệm người dùng. Khi bạn có rất nhiều hoạt động đang diễn ra, bạn muốn có chúng NHANH CHÓNG!
philipp

13
không đá con ngựa chết, tôi cũng nói rằng câu hỏi về tốc độ và khả năng đọc là không liên quan trong trường hợp này, bởi vì câu hỏi đã được gắn thẻ theo tối ưu hóa. Lý do muốn tốc độ trong một câu hỏi được gắn thẻ tối ưu hóa là tự giải thích.
CompleteNotLizards

Câu trả lời:


371

Tôi vừa thiết lập một bài tập điểm chuẩn nhanh:

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

Trung bình, gọi intval () chậm hơn hai lần rưỡi và sự khác biệt là lớn nhất nếu đầu vào của bạn đã là một số nguyên.

Tôi muốn biết tại sao mặc dù.


Cập nhật: Tôi đã chạy thử nghiệm lần nữa, lần này với sự ép buộc (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   |
|-----------------|------------|-----------|-----------|

Phụ lục: Tôi vừa gặp một hành vi hơi bất ngờ mà bạn nên biết khi chọn một trong các phương pháp sau:

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

Đã thử nghiệm bằng PHP 5.3.1


9
Có lẽ có một cái gì đó để làm với thực tế là intval () gọi một cuộc gọi hàm, trong khi diễn viên được xử lý trực tiếp trong máy tính biểu thức của trình thông dịch. Đây cũng có thể là lý do một sự ép buộc thậm chí còn nhanh hơn.
staticsan

10
Ví dụ cưỡng chế của bạn có thể được đơn giản hóa hơn nữa bằng cách sử dụng toán tử cộng đơn ít được biết đến của php. $ x + 0 -> + $ x
Ozzy

@Ozzy Thật tuyệt vời. Cảm ơn vì tiền hỗ trợ! +"15" == 15
caiosm1005

1
@ John vì anh ta chỉ kiểm tra hai trường hợp trong mã đầu tiên đó, (int)intval, trong mỗi cặp, cho% trên intval, trường hợp cơ sở phải là (int). Nhưng bạn có một điểm tốt là nó sẽ rõ ràng hơn nếu anh ấy nói một cách rõ ràng, đặc biệt là sau khi anh ấy thêm trường hợp thứ ba!
ToolmakerSteve

2
Có bất kỳ thay đổi nào đối với kết quả này trong các phiên bản PHP mới hơn không?
Artyom

34

Cá nhân tôi cảm thấy đúc là đẹp nhất.

$iSomeVar = (int) $sSomeOtherVar;

Nếu một chuỗi như 'Xin chào' được gửi, nó sẽ được chuyển thành số nguyên 0. Đối với một chuỗi như '22 tuổi ', nó sẽ được chuyển thành số nguyên 22. Bất cứ điều gì nó không thể phân tích thành một số đều trở thành 0.

Nếu bạn thực sự CẦN tốc độ, tôi đoán những gợi ý khác ở đây là chính xác khi cho rằng sự ép buộc là nhanh nhất.


7
thật thú vị, các mảng được chuyển thành 1. đi hình.
nickf

2
@nickf Không phải vậy - Nó cũng có thể được chuyển thành 0. Nó biến giá trị boolean (true | false) của nó thành một số nguyên - 'false' = 0, 'true' = 1. Một mảng là sai nếu nó trống 100% và nó đúng nếu nó chứa BẤT K data dữ liệu nào, ngay cả khi nó chỉ trống chuỗi hoặc giá trị NULL. Nếu bạn chuyển một mảng trống thành một số nguyên, nó sẽ trở thành 0. (Vâng, tôi biết điều này cũ!)
Super Cat

15

Chạy thử nghiệm.

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

Đây là một thử nghiệm chạy mỗi kịch bản 10.000.000 lần. :-)

Đồng ercion là 0 + "123"

Đúc là (integer)"123"

Tôi nghĩ Co-ercion nhanh hơn một chút. Ồ, và cố gắng 0 + array('123')là một lỗi nghiêm trọng trong PHP. Bạn có thể muốn mã của mình kiểm tra loại giá trị được cung cấp.

Mã kiểm tra của tôi là dưới đây.


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

Tôi đã thêm vào settypethử nghiệm này và chạy nó bằng PHP 7. Cast xuất hiện một chút ở phía trước và một cải tiến hiệu suất lớn so với tất cả: chuỗi coced: 1.9255340099335 chuỗi đúc: chuỗi 1.5142338275909 chuỗi settype: 4.149735212326 chuỗi bị lỗi: 1.2346560955048 chuỗi không thành công settype: 4.149735212326
bstoney

9

Bạn chỉ có thể chuyển đổi chuỗi dài thành số nguyên bằng cách sử dụng FLOAT

$float = (float)$num;

Hoặc nếu bạn muốn số nguyên không nổi val thì hãy đi với

$float = (int)$num;

Dành cho người cũ

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

1
Huh? Nếu bạn muốn một int, tại sao bạn không sử dụng (int)? Có thể đúng là nếu chuỗi chứa một số nguyên, nó (float)sẽ trả về một giá trị hoạt động rất giống một số nguyên (mặc dù kiểu bên trong của nó có thể float), nhưng tại sao bạn lại làm điều này, nếu đặc tả là trả về một giá trị nguyên ? Giả sử chuỗi đến là "1.3"? Bạn sẽ không nhận được một số nguyên. Ngoài ra, vì lợi ích của bất kỳ ai đọc mã trong tương lai, bạn nên nói ý của bạn. Nếu bạn có nghĩa là "nó nên là một số nguyên", thì nói (int), không (float).
ToolmakerSteve

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

3
Tôi tin rằng một số tài liệu tham khảo hoặc bằng chứng là theo thứ tự!
Mehran

$ int thực sự sẽ là một boolean ở đây, nếu câu lệnh hoạt động, nhưng nó sẽ không vì tham số đầu tiên của settype () được truyền bằng tham chiếu và do đó phải là một var.
Xếp hàng

7

trích xuất số nguyên từ bất kỳ chuỗi

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

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

// $ out = '1231233';


Bạn là tốt nhất của tốt nhất của tốt nhất! Tôi đã dành hàng giờ để chuyển đổi một số var từ chuỗi dữ liệu json sang số nguyên, chỉ có phương pháp của bạn mới giúp được! cảm ơn bạn!
Kamnibula

4

Thêm kết quả điểm chuẩn 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

Sẽ tốt hơn nếu viết câu lệnh đang được kiểm tra 10 lần trong mỗi vòng lặp, để thời gian không bị chi phối bởi chi phí vòng lặp. Ví dụ { $i = +"-11"; $i = +"-11"; $i= +"-11"; $i= +"-11"; ... }. Việc sử dụng "-11"trực tiếp giá trị theo nghĩa đen cũng rất rủi ro , trừ khi bạn chắc chắn rằng ngôn ngữ sẽ không thực hiện một số công việc vào thời gian biên dịch. Có lẽ OK cho một ngôn ngữ động như PHP, nhưng tôi đề cập đến để tham khảo trong tương lai nếu thử nghiệm các công thức trong các ngôn ngữ khác. An toàn hơn để đặt một biến $x = "-11"trước vòng lặp kiểm tra, và sau đó sử dụng nó. Vì vậy, mã bên trong là $i =+$x.
ToolmakerSteve

4

Chạy một điểm chuẩn và hóa ra cách nhanh nhất để có được một số nguyên thực (sử dụng tất cả các phương thức có sẵn) là

$foo = (int)+"12.345";

Chỉ cần sử dụng

$foo = +"12.345";

trả lại một cái phao.


2
Điều này nhanh hơn đơn giản (int)"12.345"? Nhanh hơn bao nhiêu phần trăm?
ToolmakerSteve
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.