PHP Conference Japan 2024

整數

int 是一種屬於集合 ℤ = {..., -2, -1, 0, 1, 2, ...} 的數字。

語法

Int 可以用十進位(以 10 為底)、十六進位(以 16 為底)、八進位(以 8 為底)或二進位(以 2 為底)表示。 負號運算子可以用來表示負的 int

若要使用八進位表示法,請在數字前加上 0(零)。自 PHP 8.1.0 起,八進位表示法也可以在前面加上 0o0O。若要使用十六進位表示法,請在數字前加上 0x。若要使用二進位表示法,請在數字前加上 0b

自 PHP 7.4.0 起,整數文字可以在數字之間包含底線 (_),以便提高文字的可讀性。這些底線會被 PHP 的掃描器移除。

範例 #1 整數文字

<?php
$a
= 1234; // 十進位數字
$a = 0123; // 八進位數字(相當於十進位的 83)
$a = 0o123; // 八進位數字(自 PHP 8.1.0 起)
$a = 0x1A; // 十六進位數字(相當於十進位的 26)
$a = 0b11111111; // 二進位數字(相當於十進位的 255)
$a = 1_234_567; // 十進位數字(自 PHP 7.4.0 起)
?>

形式上,自 PHP 8.1.0 起,int 文字的結構如下(先前不允許 0o0O 八進位前綴,且在 PHP 7.4.0 之前不允許使用底線):

decimal     : [1-9][0-9]*(_[0-9]+)*
            | 0

hexadecimal : 0[xX][0-9a-fA-F]+(_[0-9a-fA-F]+)*

octal       : 0[oO]?[0-7]+(_[0-7]+)*

binary      : 0[bB][01]+(_[01]+)*

integer     : decimal
            | hexadecimal
            | octal
            | binary

int 的大小與平台有關,儘管最大值通常約為 20 億(即 32 位元有號數)。 64 位元平台的最大值通常約為 9E18。PHP 不支援無號 intint 的大小可以使用常數 PHP_INT_SIZE 來確定,最大值可以使用常數 PHP_INT_MAX 來確定,最小值可以使用常數 PHP_INT_MIN 來確定。

整數溢位

如果 PHP 遇到超出 int 型別範圍的數字,則會將其解釋為 float。 此外,運算結果超出 int 型別範圍的數字也會傳回 float

範例 #2 整數溢位

<?php
$large_number
= 50000000000000000000;
var_dump($large_number); // float(5.0E+19)

var_dump(PHP_INT_MAX + 1); // 32 位元系統:float(2147483648)
// 64 位元系統:float(9.2233720368548E+18)
?>

整數除法

PHP 中沒有 int 除法運算子,若要達成此目的,請使用 intdiv() 函式。 1/2 會產生 float 0.5。 可以將值強制轉換為 int 以將其向零捨去,或者 round() 函式提供更精細的捨去控制。

<?php
var_dump
(25/7); // float(3.5714285714286)
var_dump((int) (25/7)); // int(3)
var_dump(round(25/7)); // float(4)
?>

轉換為整數

若要將值明確轉換為 int,請使用 (int)(integer) 強制轉換。 然而,在大多數情況下,不需要強制轉換,因為如果運算子、函式或控制結構需要 int 引數,則會自動轉換值。 也可以使用 intval() 函式將值轉換為 int

如果將 resource 轉換為 int,則結果將會是 PHP 在執行階段指派給 resource 的唯一資源編號。

另請參閱 型別處理

布林值

false 將產生 0(零),而 true 將產生 1(一)。

浮點數

float 轉換為 int 時,數字將會向零捨去。 自 PHP 8.1.0 起,當將非整數 float 隱式轉換為 int 且遺失精確度時,會發出棄用通知。

<?php

function foo($value): int {
return
$value;
}

var_dump(foo(8.1)); // 自 PHP 8.1.0 起:「Deprecated: Implicit conversion from float 8.1 to int loses precision」
var_dump(foo(8.1)); // 在 PHP 8.1.0 之前為 8
var_dump(foo(8.0)); // 在兩種情況下皆為 8

var_dump((int) 8.1); // 在兩種情況下皆為 8
var_dump(intval(8.1)); // 在兩種情況下皆為 8
?>

如果浮點數超出 int 的界限(通常在 32 位元平台上為 +/- 2.15e+9 = 2^31,在 64 位元平台上為 +/- 9.22e+18 = 2^63),則結果是未定義的,因為 float 沒有足夠的精確度來給出確切的 int 結果。當這種情況發生時,不會發出警告,甚至連通知也不會發出!

注意:

當轉換為 int 時,NaNInf-Inf 將始終為零。

警告

永遠不要將未知的分數轉換為 int,因為這有時可能會導致意想不到的結果。

<?php
echo (int) ( (0.1+0.7) * 10 ); // 輸出 7!
?>

另請參閱關於浮點數精確度的警告

從字串轉換

如果字串是數值或前導數值,則它將解析為相應的整數值,否則將轉換為零(0)。

NULL 轉換

null 始終轉換為零(0)。

從其他類型轉換

注意

對於其他類型,轉換為 int 的行為是未定義的。不要依賴任何觀察到的行為,因為它可能會在不通知的情況下發生變化。

新增註解

使用者貢獻的註解 10 則註解

php at richardneill dot org
11 年前
數值文字中的前導零表示「這是八進位」。但請不要混淆:字串中的前導零則不然。因此
$x = 0123; // 83
$y = "0123" + 0 // 123
d_n at NOSPAM dot Loryx dot com
17 年前
以下是一些將「點分」IP 位址轉換為 LONG int,以及反向轉換的技巧。這非常有用,因為如果 IP 位址以 BIGINT 而不是字元形式儲存在資料庫表格中,則存取速度會快得多。

IP 轉 BIGINT
<?php
$ipArr
= explode('.',$_SERVER['REMOTE_ADDR']);
$ip = $ipArr[0] * 0x1000000
+ $ipArr[1] * 0x10000
+ $ipArr[2] * 0x100
+ $ipArr[3]
;
?>

從資料庫讀取以 BIGINT 形式儲存的 IP 位址轉換回點分形式

請記住,PHP 整數運算子是 INTEGER -- 而不是 long。此外,由於 PHP 中沒有整數除法,我們透過位元平移節省了幾個 S-L-O-W floor (<division>) 運算。我們必須對 $ipArr[0] 使用 floor(/),因為儘管 $ipVal 儲存為 long 值,但 $ipVal >> 24 將在 $ipVal 的截斷整數值上運作!然而,$ipVint 是一個很好的整數,所以
我們可以享受位元平移。

<?php
$ipVal
= $row['client_IP'];
$ipArr = array(0 =>
floor( $ipVal / 0x1000000) );
$ipVint = $ipVal-($ipArr[0]*0x1000000); // 為了清楚起見
$ipArr[1] = ($ipVint & 0xFF0000) >> 16;
$ipArr[2] = ($ipVint & 0xFF00 ) >> 8;
$ipArr[3] = $ipVint & 0xFF;
$ipDotted = implode('.', $ipArr);
?>
ganlvtech at qq dot com
4 年前
注意浮點數轉換為整數時的溢位

<?php

// 您可能預期這些
var_dump(0x7fffffffffffffff); // int(9223372036854775807)
var_dump(0x7fffffffffffffff + 1); // float(9.2233720368548E+18)
var_dump((int)(0x7fffffffffffffff + 1)); // int(9223372036854775807)
var_dump(0x7fffffffffffffff + 1 > 0); // bool(true)
var_dump((int)(0x7fffffffffffffff + 1) > 0); // bool(true)
var_dump((int)'9223372036854775807'); // int(9223372036854775807)
var_dump(9223372036854775808); // float(9.2233720368548E+18)
var_dump((int)'9223372036854775808'); // int(9223372036854775807)
var_dump((int)9223372036854775808); // int(9223372036854775807)

// 但實際上,它像這樣
var_dump(0x7fffffffffffffff); // int(9223372036854775807)
var_dump(0x7fffffffffffffff + 1); // float(9.2233720368548E+18)
var_dump((int)(0x7fffffffffffffff + 1)); // int(-9223372036854775808) <-----
var_dump(0x7fffffffffffffff + 1 > 0); // bool(true)
var_dump((int)(0x7fffffffffffffff + 1) > 0); // bool(false) <-----
var_dump((int)'9223372036854775807'); // int(9223372036854775807)
var_dump(9223372036854775808); // float(9.2233720368548E+18)
var_dump((int)'9223372036854775808'); // int(9223372036854775807)
var_dump((int)9223372036854775808); // int(-9223372036854775808) <-----

?>

當您嘗試將其與零進行比較,或從另一個值(例如金錢)中減去時,這些溢位是危險的。
egwayjen at gmail dot com
7 年前
「PHP 中沒有整數除法運算子」。但自 PHP 7 起,有了 intdiv 函式。
dhairya lakhera
7 年前
-------------------------------------------------------------------------
問題
var_dump((int) 010); //輸出 8

var_dump((int) "010"); //輸出 10

第一個是八進位表示法,所以輸出是正確的。但是當將 "010" 轉換為整數時呢?它應該也輸出 8 嗎?
--------------------------------------------------------------------------
答案

使用 (int) 強制轉換為整數時,總是會轉換為預設的基數,即 10 進位。

以這種方式將字串強制轉換為數字時,不會考慮 PHP 中格式化整數值的多種方式(八進位的開頭零、十六進位的開頭 "0x"、二進位的開頭 "0b")。它只會查看字串中的前幾個字元,並將它們轉換為 10 進位的整數。開頭的零會被剝除,因為它們在數值中沒有意義,因此 (int)"010" 的結果會是十進位的 10。

使用 (int)010 在不同進位之間轉換整數值時,會考慮到格式化整數的各種方式。像 010 這樣開頭的零表示該數字為八進位表示法,使用 (int)010 會將其轉換為十進位的 8。

這類似於您如何使用 0x10 來寫入十六進位(基數 16)表示法。使用 (int)0x10 會將其轉換為十進位的 16,而使用 (int)"0x10" 的結果會是十進位的 0:因為 "x" 不是數值,所以之後的所有內容都會被忽略。

如果您想將字串 "010" 解釋為八進位值,您需要指示 PHP 這樣做。intval("010", 8) 會將數字解釋為 8 進位,而不是預設的 10 進位,您會得到十進位的 8。您也可以使用 octdec("010") 將八進位字串轉換為十進位的 8。另一種選擇是使用 base_convert("010", 8, 10) 將數字 "010" 從 8 進位明確轉換為 10 進位,但是此函數會傳回字串 "8" 而不是整數 8。

將字串強制轉換為整數遵循 intval 函數使用的相同邏輯。

傳回變數的整數值,使用指定的基數進行轉換(預設為基數 10)。
intval 允許將不同的基數指定為第二個參數,而直接強制轉換操作則不允許,因此使用 (int) 總是會將字串視為 10 進位。

php > var_export((int) "010");
10
php > var_export(intval("010"));
10
php > var_export(intval("010", 8));
8
匿名
17 年前
為了在某些函數中強制正確使用 32 位元無號整數,只需在處理它們之前加上 '+0' 即可。

例如
echo(dechex("2724838310"));
將印出 '7FFFFFFF'
但它應該印出 'A269BBA6'

當加上 '+0' 時,php 會正確處理 32 位元無號整數
正確地
echo(dechex("2724838310"+0));
將印出 'A269BBA6'
lewismoten at gmail dot com
5 個月前
關於 `PHP 不支援無號整數` 的部分,當使用與 PHP_INT_MIN 相符的硬式編碼有號整數最小值時,經常會造成許多混淆。

<?php
// 64 位元範例
var_dump(PHP_INT_MIN);
var_dump(-9223372036854775808);
var_dump(PHP_INT_MIN === -9223372036854775808);
// int(-9223372036854775808)
// float(-9.223372036854776E+18)
// bool(false)
?>

雖然在視覺上,我輸入了與 PHP_INT_MIN 寫出的相同值 `-9223372036854775808`,但語言剖析器只將其理解為兩個運算式,一個否定運算子後跟 `9223372036854775808`。該值超過整數的最大值 1,並被升級為浮點數。雖然過去有人建議設置一個鉤子來專門尋找這個值,但它比聽起來更困難。詞法分析器無法將否定和整數都評估為一個符號。此外,您還需要處理二進位、八進位和十六進位字面值。

<?php
var_dump
(-9223372036854775808); // 字面十進位
var_dump(-0x8000000000000000); // 字面十六進位
var_dump(-0b1000000000000000000000000000000000000000000000000000000000000000); // 字面二進位
var_dump(-01000000000000000000000); // 字面八進位
?>

如果您需要硬式編碼最小值,請使用 `PHP_INT_MIN`。它是專門為這個邊緣情況引入的。另一種方法是寫 ` -9223372036854775807 - 1`。
rustamabd@gmail-you-know-what
17 年前
請小心在大數字上使用模數運算,它會將浮點參數轉換為整數,並可能傳回錯誤的結果。例如
<?php
$i
= 6887129852;
echo
"i=$i\n";
echo
"i%36=".($i%36)."\n";
echo
"alternative i%36=".($i-floor($i/36)*36)."\n";
?>
將輸出
i=6.88713E+009
i%36=-24
alternative i%36=20
匿名
9 年前
只有當輸入以數字開頭時,轉換為整數才會有效
(int) "5txt" // 將輸出整數 5
(int) "before5txt" // 將輸出整數 0
(int) "53txt" // 將輸出整數 53
(int) "53txt534text" // 將輸出整數 53
litbai
8 年前
<?php
$ipArr
= explode('.', $ipString);
$ipVal = ($ipArr[0] << 24)
+ (
$ipArr[1] << 16)
+ (
$ipArr[2] << 8)
+
$ipArr[3]
;
?>
1. 位元運算的優先順序低於 '+',因此應該使用括號。
2. PHP 中沒有無號整數,如果您使用 32 位元版本,當 IP 字串的第一個位置大於 127 時,上面的程式碼將會得到負數結果。
3. 程式碼實際執行的操作是計算從 IP 字串轉換而來的 32 位元二進位的整數值。
To Top