【临时解决】php int 32 64,关于64位PHP仍然使用32位数字的问题
首先,我们知道有两个常量。PHP_INT_MAX和PHP_INT_SIZE。
根据PHP官方手册所说,整型数的字长和平台有关,尽管通常最大值是大约二十亿(32 位有符号)。64 位平台下的最大值通常是大约 9E18。PHP 不支持无符号整数。Integer 值的字长可以用常量 PHP_INT_SIZE来表示,自 PHP 4.4.0 和 PHP 5.0.5后,最大值可以用常量 PHP_INT_MAX 来表示。
但是,当我们在Windows下使用64位PHP(版本5.6.4和5.2.17)的时候,PHP_INT_SIZE为4,PHP_INT_MAX为2^31-1。与之相反的是,如果在Linux下使用64位PHP,PHP_INT_SIZE为8,PHP_INT_MAX为2^63-1。PHP Bugs官方也有这么一条BUG报告:
https://bugs.php.net/bug.php?id=64863
以下是我的输出
D:\Website\IIS>cat int.php
echo 'PHP_VERSION = ' . PHP_VERSION . "\n";
echo 'PHP_INT_MAX = ' . PHP_INT_MAX . "\n";
echo 'PHP_INT_SIZE = ' . PHP_INT_SIZE . "\n";
D:\Website\IIS>php int.php
PHP_VERSION = 5.6.4
PHP_INT_MAX = 2147483647
PHP_INT_SIZE = 4
D:\Website\IIS>php --version
PHP 5.6.4 (cli) (built: Dec 17 2014 13:23:31)
Copyright (c) 1997-2014 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2014 Zend Technologies
with Xdebug v2.2.7, Copyright (c) 2002-2015, by Derick Rethans
为什么呢?
还是查代码。
我们可以在PHP的main/main.c中查到
REGISTER_MAIN_LONG_CONSTANT("PHP_INT_SIZE", sizeof(long), CONST_PERSISTENT | CONST_CS);
嗯,那看来和C语言的long长度有关。那应该是编译器的问题了。
我们知道,PHP在Windows下用的VC++编译器。那试试看咯。
先上代码
#include
using namespace std;
int main() {
cout <
cout <
cout <
return 0;
}
首先是在x86下编译的结果
Z:\>cl /EHsc int.cpp && int
Microsoft (R) C/C++ Optimizing Compiler Version 17.00.60610.1 for x86
Copyright (C) Microsoft Corporation. All rights reserved.
int.cpp
Microsoft (R) Incremental Linker Version 11.00.60610.1
Copyright (C) Microsoft Corporation. All rights reserved.
/out:int.exe
int.obj
int (size = 4) max = 2147483647
long (size = 4) max = 2147483647
llong (size = 8) max = 9223372036854775807
再用64位编译器编译吧。
Z:\>cl /EHsc int.cpp && int
Microsoft (R) C/C++ Optimizing Compiler Version 17.00.60610.1 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
int.cpp
Microsoft (R) Incremental Linker Version 11.00.60610.1
Copyright (C) Microsoft Corporation. All rights reserved.
/out:int.exe
int.obj
int (size = 4) max = 2147483647
long (size = 4) max = 2147483647
llong (size = 8) max = 9223372036854775807
嗯,很好,我们用g++编译器编译呢?
$ g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-cygwin/4.8.3/lto-wrapper.exe
Target: x86_64-pc-cygwin
Configured with: /cygdrive/i/szsz/tmpp/cygwin64/gcc/gcc-4.8.3-2/src/gcc-4.8.3/configure --srcdir=/cygdrive/i/szsz/tmpp/c
ygwin64/gcc/gcc-4.8.3-2/src/gcc-4.8.3 --prefix=/usr --exec-prefix=/usr --bindir=/usr/bin --sbindir=/usr/sbin --libexecdi
r=/usr/libexec --datadir=/usr/share --localstatedir=/var --sysconfdir=/etc --libdir=/usr/lib --datarootdir=/usr/share --
docdir=/usr/share/doc/gcc --htmldir=/usr/share/doc/gcc/html -C --build=x86_64-pc-cygwin --host=x86_64-pc-cygwin --target
=x86_64-pc-cygwin --without-libiconv-prefix --without-libintl-prefix --enable-shared --enable-shared-libgcc --enable-sta
tic --enable-version-specific-runtime-libs --enable-bootstrap --disable-__cxa_atexit --with-dwarf2 --with-tune=generic -
-enable-languages=ada,c,c++,fortran,lto,objc,obj-c++ --enable-graphite --enable-threads=posix --enable-libatomic --enabl
e-libgomp --disable-libitm --enable-libquadmath --enable-libquadmath-support --enable-libssp --enable-libada --enable-li
bgcj-sublibs --disable-java-awt --disable-symvers --with-ecj-jar=/usr/share/java/ecj.jar --with-gnu-ld --with-gnu-as --w
ith-cloog-include=/usr/include/cloog-isl --without-libiconv-prefix --without-libintl-prefix --with-system-zlib --libexec
dir=/usr/lib
Thread model: posix
gcc version 4.8.3 (GCC)
sx@zsx-pc /cygdrive/z
$ g++ int.cpp -o int & ./int
[1] 25508
int (size = 4) max = 2147483647
long (size = 8) max = 9223372036854775807
llong (size = 8) max = 9223372036854775807
比较一下这两个编译器long的size和max,就能知道为什么在老版本PHP中INT_MAX的值不一样了。
REGISTER_MAIN_LONG_CONSTANT("PHP_INT_SIZE", SIZEOF_ZEND_LONG, CONST_PERSISTENT | CONST_CS);
所以,PHP7中,应该不会再出现这个问题了。
Windows系统下64位PHP中PHP_INT_MAX为32位
相信很多在Windows环境开发的人都遇到一个问题,就是从数据库里取出的int值比64位PHP里面的int值大,导致用intval过滤之后,数值不准确。
Mysql中int分有符号和无符号,有符合的最大值为:2147483647 ,无符号的最大值为:4294967295。
理论上64位的PHP的PHP_INT_SIZE是:8 ,PHP_INT_MAX是:9223372036854775807。
实际上在Linux系统下64位PHP的PHP_INT_MAX的值是:9223372036854775807 ,但是在Windows系统下输出64位PHP的PHP_INT_MAX的值却是:2147483647。
通过查看PHP源码中PHP_INT_SIZE的定义:
1 |
|
可以看到PHP_INT_SIZE的大小是与C语言的long类型长度一样的。
PHP在Windows平台是用VC++编译的,在Linux平台是用g++编译的。查了一下关于这两个编译器在64位环境的资料:
VC++(64位) | g++(64位) | |
int | 4 | 4 |
long | 4 | 8 |
long long | 8 | 8 |
原来在64位编译环境中VC++和g++的long类型长度是有差别的。所以Windows下64位的PHP的int会比Mysql中无符号的int小。
在不升级php版本的情况下,如何解决这个问题呢?临时改动项目:
在框架中将
return PHP_INT_MAX > 2147483647;
改为
return PHP_INT_MAX +1 > 2147483647;
赞赏码
非学,无以致疑;非问,无以广识