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 的大小取决于平台,尽管最大值通常约为二十亿(即 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 开始,当隐式转换非整数 floatint 并丢失精度时,会发出弃用通知。

<?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结果。发生这种情况时,不会发出警告,甚至不会发出通知!

注意:

NaNInf-Inf转换为int时始终为零。

警告

切勿将未知分数转换为int,因为这有时会导致意外结果。

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

另请参见有关浮点数精度警告

来自字符串

如果字符串是数字的或以数字开头,则它将解析为相应的整数值,否则它将转换为零(0)。

来自NULL

null始终转换为零(0)。

来自其他类型

警告

将其他类型转换为int的行为是未定义的。请勿依赖任何观察到的行为,因为它可能会在未经通知的情况下更改。

添加注释

用户贡献的注释 10条注释

139
php at richardneill dot org
11年前
数字文字中的前导零表示“这是八进制”。但不要混淆:字符串中的前导零并非如此。因此
$x = 0123; // 83
$y = "0123" + 0 // 123
57
d_n at NOSPAM dot Loryx dot com
17年前
以下是一些将“点分十进制”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);
?>
17
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) <-----

?>

当尝试将其与零进行比较或从另一个值(例如金钱)中减去它时,这些溢出会很危险。
19
egwayjen at gmail dot com
7年前
“PHP中没有整数除法运算符”。但从PHP 7开始,就有intdiv函数。
17
dhairya lakhera
7年前
-------------------------------------------------------------------------
问题
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
13
匿名用户
17年前
为了强制在某些函数中正确使用 32 位无符号整数,只需在处理它们之前添加 '+0'。

例如
echo(dechex("2724838310"));
将打印 '7FFFFFFF'
但它应该打印 'A269BBA6'

添加 '+0' 后,php 将正确处理 32 位无符号整数。
正确地
echo(dechex("2724838310"+0));
将打印 'A269BBA6'
1
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`。
12
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
7
匿名用户
9 年前
转换为整数只有在输入以数字开头时才有效。
(int) "5txt" // 将输出整数 5
(int) "before5txt" // 将输出整数 0
(int) "53txt" // 将输出整数 53
(int) "53txt534text" // 将输出整数 53
4
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