1. Einführung
Intern werden alle Integerwerte als Binärzahlen gespeichert. Abhängig vom System und der verwendeten PHP-Version stehen 32 oder 64 bit pro Integer zur Verfügung. Ein Bit fällt jeweils weg, um zu kennzeichnen, ob die Zahl positiv oder negativ ist. Bei n zur Verfügung stehenden Bit ergibt sich der größte Dezimalwert, der abgebildet werden kann, aus n2-1. (Für das -1 kann man etwa eine Zahl mit einem Bit betrachten, welche maximal den Dezimalwert 1 abbilden kann.)
2. PHP_INT_MAX
Nachfolgend wird eine 32bit-Version von PHP verwendet. Der größte Dezimalwert lautet für diese Version demnach (32-1)2-1 (ca. 2,1 Milliarden). Dieser Wert ist in der Konstante PHP_INT_MAX abgespeichert, man muss ihn also nicht selbst ausrechnen.
<?php var_dump(PHP_INT_MAX + 2); var_dump(PHP_INT_MAX + 1); var_dump(PHP_INT_MAX); var_dump(PHP_INT_MAX - 1); var_dump(PHP_INT_MAX - 2); ?>
float(2147483649) float(2147483648) int(2147483647) int(2147483646) int(2147483645)
Wie im Beispiel zu sehen ist, werden alle Werte bis 312-1 (also 2147483647) als Integer gespeichert. Über diesen Wert hinaus wechselt PHP automatisch zu Float. Im Gegensatz zu anderen Sprachen entsteht also weder eine Fehlermeldung, noch wechselt die Zahl in den negativen Bereich. So ist die Durchführung der meisten Rechnungen zwar noch möglich, kleinere Abweichungen vom erwarteten Wert können sich jedoch ergeben. Insbesondere bei Prüfungen auf Gleichheit kann es bei Floats zu unerwartetem Verhalten kommen. Integer Overflows sollten daher generell vermieden werden.
3. PHP_INT_MIN
Die Konstante „PHP_INT_MIN” ist in PHP nicht vordefiniert. Sie lässt sich aber einfach nachbilden, indem man PHP_INT_MAX*(-1) rechnet.
<?php define('PHP_INT_MIN', PHP_INT_MAX * (-1)); var_dump(PHP_INT_MIN + 2); var_dump(PHP_INT_MIN + 1); var_dump(PHP_INT_MIN); var_dump(PHP_INT_MIN - 1); var_dump(PHP_INT_MIN - 2); ?>
int(-2147483645) int(-2147483646) int(-2147483647) int(-2147483648) float(-2147483649)
In diesem Beispiel beginnt der Wechsel zu Float erst bei (PHP_INT_MAX*(-1) - 1), also nach -2147483648. Wie im nächsten Abschnitt zu sehen ist, sollte man dennoch PHP_INT_MIN nicht als (PHP_INT_MAX*(-1) - 1) definieren.
4. Abweichungen bei Rechnung ohne Konstanten
Zunächst einmal die Ausgaben, wenn man statt (PHP_INT_MAX +/- x) direkt die gewünschten Integerwerte verwendet:
<?php var_dump(2147483649); var_dump(2147483648); var_dump(2147483647); ?>
float(2147483649) float(2147483648) int(2147483647)
Das Ergebnis zeigt gegenüber den vorherigen Rechnungen keine Abweichungen und deckt sich daher mit den Erwartungen. Anders sieht es aus, wenn man in den negativen Bereich geht:
<?php var_dump(-2147483647); var_dump(-2147483648); var_dump(-2147483649); // zum Vergleich noch mal der Minimalwert, ausgerechnet via PHP_INT_MAX: var_dump(PHP_INT_MAX*(-1) - 1); ?>
int(-2147483647) float(-2147483648) float(-2147483649) int(-2147483648)
Die direkte Verwendung von -2147483648 führt also zu einem anderen Ergebnis als die Berechnung des Wertes über PHP_INT_MAX: PHP wechselt bereits eine Stelle früher zu Float. Der Grund dafür ist vermutlich ein PHP-Bug. (Freilich hat dieses Verhalten nur eher akademische Bedeutung und keine wirklichen Auswirkungen auf die Praxis.)