サンプル・プログラム
overflow.php | サンプル・プログラム本体。 |
pahooInputData.php | データ入力に関わる関数群。 使い方は「PHPでGET/POSTでフォームから値を受け取る」「数値入力とバリデーション」「文字入力とバリデーション」などを参照。include_path が通ったディレクトリに配置すること。 |
integer 型の制約
  52: /**
  53: * integer型のオーバーフローを見る
  54: * @param なし
  55: * @return なし
  56: */
  57: function overflow1() {
  58: echo '■integer型のオーバーフロー/アンダーフローを見る<br />';
  59: echo 'PHP_INT_SIZE = ' . PHP_INT_SIZE . '<br />'; //integer型のバイト長
  60: echo 'PHP_INT_MAX = ' . PHP_INT_MAX . '<br />'; //integer型の最大値
  61: echo '<hr />';
  62: //正数のオーバーフロー
  63: $a = PHP_INT_MAX - 2;
  64: for ($i = 0; $i < 5; $i++) {
  65: var_dump($a);
  66: echo '<br />';
  67: $a++;
  68: }
  69: echo '<hr />';
  70: //負数のアンダーフロー
  71: $a = 0 - PHP_INT_MAX;
  72: for ($i = 0; $i > -5; $i--) {
  73: var_dump($a);
  74: echo '<br />';
  75: $a--;
  76: }
  77: }
実際には32ビット環境と64ビット環境で変わり、以下のようになっている。
ビット長 | PHP_INT_SIZE | PHP_INT_MAX | |
32ビット環境 | 32ビット | 4 | 2,147,483,647 |
64ビット環境 | 64ビット | 8 | 9,223,372,036,854,775,807 |
■32ビット環境
PHP_INT_SIZE = 4
PHP_INT_MAX = 2,147,483,647
-231 ≦ integer ≦ 231 - 1
-2,147,483,648 ≦ integer ≦ 2,147,483,647
■64ビット環境
PHP_INT_SIZE = 8
PHP_INT_MAX = 9,223,372,036,854,775,807
-263 ≦ integer ≦ 263 - 1
-9,223,372,036,854,775,808 ≦ integer ≦ 9,223,372,036,854,775,807
プログラムを実行すると、この制約を上回る/下回ると、integer 型から float 型へ自動的に移行するのが分かる。
float型から integer型へは自動移行しない
  79: /**
  80: * float型からinteger型へは自動移行しない
  81: * @param なし
  82: * @return なし
  83: */
  84: function overflow2() {
  85: echo '■float型からinteger型へは自動移行しない<br />';
  86: //正数
  87: $a = PHP_INT_MAX + 2;
  88: for ($i = 5; $i > 0; $i--) {
  89: var_dump($a);
  90: echo '<br />';
  91: $a--;
  92: }
  93: echo '<hr />';
  94: //負数
  95: $a = -3 - PHP_INT_MAX;
  96: for ($i = -5; $i < 0; $i++) {
  97: var_dump($a);
  98: echo '<br />';
  99: $a++;
 100: }
 101: }
もし integer 型にしたいのであれば、強制的にキャストしてやる必要がある。
float 型の制約と誤差
 103: /**
 104: * float型のオーバーフローを見る
 105: * @param なし
 106: * @return なし
 107: */
 108: function overflow3() {
 109: echo '■float型のオーバーフロー/アンダーフローを見る<br />';
 110: //float型のオーバーフロー(大数側)
 111: $a = +1.79E+305;
 112: for ($i = 0; $i < 5; $i++) {
 113: var_dump($a);
 114: echo '<br />';
 115: $a *= 10;
 116: }
 117: echo '<hr />';
 118: //float型のオーバーフロー(小数側)
 119: $a = +4.94E-323;
 120: for ($i = 0; $i < 5; $i++) {
 121: var_dump($a);
 122: echo '<br />';
 123: $a /= 10;
 124: }
 125: echo '<hr />';
 126: //float型のアンダーフロー(大数側)
 127: $a = -1.79E+305;
 128: for ($i = 0; $i < 5; $i++) {
 129: var_dump($a);
 130: echo '<br />';
 131: $a *= 10;
 132: }
 133: echo '<hr />';
 134: //float型のアンダーフロー(小数側)
 135: $a = -4.94E-323;
 136: for ($i = 0; $i < 5; $i++) {
 137: var_dump($a);
 138: echo '<br />';
 139: $a /= 10;
 140: }
 141: }
つまり、絶対値の範囲は下記の通りである。
4.9406564584124654E-324 ≦ float ≦ 1.7976931348623157E+308
これをプログラムで確かめると、この範囲をオーバーフローすると 'INF' または '0' になる、逆にアンダーフローすると '-INF' または '-0' になることが分かる。INFは無限大を意味する。
また、10で除算しているにもかかわらず、2進数特有の“誤差”が発生していることも分かる。
これほどの大きさ/小ささの数値データを扱うことは希だろうが、もしループ処理内でオーバーフロー/アンダーフローしてしまうとINFや0が返るので、PHP処理系ではエラーを出さずに無限ループに陥る恐れがある。注意しておきたいところだ。
制約を超えると演算が正常に行われなくなり、プログラム全体の動作がおかしくなる場合がある。最悪の場合、プログラムが無限ループに陥ったり、思わぬエラーを晒したりする恐れがあるので、セキュリティ上、注意が必要だ。