数字文字中的前导零表示“这是八进制”。但不要混淆:字符串中的前导零并非如此。因此
$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 的大小取决于平台,尽管最大值通常约为二十亿(即 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开始,“弃用:从浮点数8.1到整数的隐式转换会丢失精度”
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结果。发生这种情况时,不会发出警告,甚至不会发出通知!
注意:
NaN
、Inf
和-Inf
转换为int时始终为零。
如果字符串是数字的或以数字开头,则它将解析为相应的整数值,否则它将转换为零(0
)。
将其他类型转换为int的行为是未定义的。请勿依赖任何观察到的行为,因为它可能会在未经通知的情况下更改。
数字文字中的前导零表示“这是八进制”。但不要混淆:字符串中的前导零并非如此。因此
$x = 0123; // 83
$y = "0123" + 0 // 123
以下是一些将“点分十进制”IP地址转换为长整数以及反向转换的技巧。这非常有用,因为如果将IP地址存储为BIGINT而不是字符,则访问数据库表中的IP地址的速度要快得多。
IP到BIGINT
<?php
$ipArr = explode('.',$_SERVER['REMOTE_ADDR']);
$ip = $ipArr[0] * 0x1000000
+ $ipArr[1] * 0x10000
+ $ipArr[2] * 0x100
+ $ipArr[3]
;
?>
从数据库读取的BIGINT格式的IP转换为点分十进制形式
请记住,PHP整数运算符是INTEGER——而不是长整数。此外,由于PHP中没有整数除法,因此我们通过执行位移来节省几次非常慢的floor(<division>)。我们必须对$ipArr[0]使用floor(/),因为虽然$ipVal存储为长整数值,但$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中格式化整数值的多种方法(基数8的前导零,“0x”表示基数16,“0b”表示基数2)。它只会查看字符串中的前几个字符并将它们转换为基数10整数。前导零将被去除,因为它们在数值中没有任何意义,因此对于(int)"010",您最终将得到十进制值10。
使用(int)010在基数之间转换整数值将考虑格式化整数的各种方法。像010这样的前导零表示该数字以八进制表示,使用(int)010将将其转换为基数10中的十进制值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 函数相同的逻辑。
返回 var 的整数值,使用指定的基数进行转换(默认为 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