數值文字中的前導零表示「這是八進位」。但請不要混淆:字串中的前導零則不然。因此
$x = 0123; // 83
$y = "0123" + 0 // 123
int 是一種屬於集合 ℤ = {..., -2, -1, 0, 1, 2, ...} 的數字。
Int 可以用十進位(以 10 為底)、十六進位(以 16 為底)、八進位(以 8 為底)或二進位(以 2 為底)表示。 負號運算子可以用來表示負的 int。
若要使用八進位表示法,請在數字前加上 0
(零)。自 PHP 8.1.0 起,八進位表示法也可以在前面加上 0o
或 0O
。若要使用十六進位表示法,請在數字前加上 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 文字的結構如下(先前不允許 0o
或 0O
八進位前綴,且在 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 不支援無號 int。 int 的大小可以使用常數 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 的唯一資源編號。
另請參閱 型別處理。
從 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 時,
NaN
、Inf
和-Inf
將始終為零。
如果字串是數值或前導數值,則它將解析為相應的整數值,否則將轉換為零(0
)。
對於其他類型,轉換為 int 的行為是未定義的。不要依賴任何觀察到的行為,因為它可能會在不通知的情況下發生變化。
數值文字中的前導零表示「這是八進位」。但請不要混淆:字串中的前導零則不然。因此
$x = 0123; // 83
$y = "0123" + 0 // 123
以下是一些將「點分」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);
?>
注意浮點數轉換為整數時的溢位
<?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) <-----
?>
當您嘗試將其與零進行比較,或從另一個值(例如金錢)中減去時,這些溢位是危險的。
-------------------------------------------------------------------------
問題
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
為了在某些函數中強制正確使用 32 位元無號整數,只需在處理它們之前加上 '+0' 即可。
例如
echo(dechex("2724838310"));
將印出 '7FFFFFFF'
但它應該印出 'A269BBA6'
當加上 '+0' 時,php 會正確處理 32 位元無號整數
正確地
echo(dechex("2724838310"+0));
將印出 'A269BBA6'
關於 `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`。
請小心在大數字上使用模數運算,它會將浮點參數轉換為整數,並可能傳回錯誤的結果。例如
<?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