【PHP】案外知られてないかもしれないintegerにキャストした際の挙動まとめ



# 公式リファレンスマニュアルを今一度読んで仕様を把握する

案外知られてない？みたいな感じだったので、なかなかに引っかかると厄介な挙動3種を以下に[^1]再まとめましたので、
知らなかった方はこの機会に公式リファレンスマニュアルを読んでみてください
という記事です。

[^1]: [公式リファレンスマニュアル](https://www.php.net/manual/ja/index.php)に全部かいてあることなので

# 未知の端数をintegerにキャストすると予期しない結果になる

- [PHP: 整数 - Manual：整数への変換](https://www.php.net/manual/ja/language.types.integer.php#language.types.integer.casting)

```php
echo (int) ( (0.1 + 0.7) * 10 );
echo "\n------------------------\n";
echo (float) ( (0.1 + 0.7) * 10 );
```

以下実行結果

```
7
------------------------
8
```

以下[float の精度に関する注意](https://www.php.net/manual/ja/language.types.float.php#warn.float-precision)から引用

> さらに、十進数では正確な小数で表せる有理数、たとえば 0.1 や 0.7 は、 二進数の浮動小数点数としては正確に表現できません。 これは、仮数部をいくら大きくしても同じです。 したがって、それを内部的な二進数表現に変換する際には、どうしても多少精度が落ちてしまいます。 その結果、不思議な結果を引き起こすことがあります。たとえば、 floor((0.1+0.7)*10) の結果はたいてい 7 となるでしょう。おそらくは 8 を想定していらっしゃるでしょうが、そのようにはなりません。 これは、(この計算結果の) 内部的な値が 7.9999999999999991118... のようになっているからです。
> 
> よって、小数の最後の桁を信用してはいけませんし、 小数を直接比較して等しいかどうかを調べてはいけません。より高い精度が必要な場合には、 任意精度数学関数または gmp 関数を代わりに使用してください。


詳細は上記のリンク先に書いてあるので読んでおきましょう

# キャストは先頭が数字で始まる文字列のみ機能する


- [PHP: 整数 - Manual：Converting to an integer works only if the input begins with a number](https://www.php.net/manual/ja/language.types.integer.php#116479)

```php
echo (int) "5txt";
echo "\n------------------------\n";
echo (int) "before5txt";
echo "\n------------------------\n";
echo (int) "53txt"; 
echo "\n------------------------\n";
echo (int) "53txt534text";
echo "\n------------------------\n";
```

以下実行結果

```
5
------------------------
0
------------------------
53
------------------------
53
------------------------
```

見ての通り、**先頭が数字で始まる文字列の数字部分しかキャストされない**ので、注意が必要です。

文字列から整数への変換に関しては以下を参考にしてください

- [PHP: 文字列 - Manual(文字列の数値への変換)](
https://www.php.net/manual/ja/language.types.string.php#language.types.string.conversion)

# 数値リテラルの先頭「0」は「8進数」と認識されるが文字列の場合その限りではない

- [PHP: 整数 - Manual：A leading zero in a numeric literal means "this is octal". But don't be confused: a leading zero in a string does not. ](https://www.php.net/manual/ja/language.types.integer.php#111523)

```php
echo "\n[先頭0の数値]------------------------\n\n";

var_dump(0123);

echo "\n[先頭0の文字列]------------------------\n\n";

var_dump("0123" + 0);
```

以下実行結果

```
[先頭0の数値]------------------------

int(83)

[先頭0の文字列]------------------------

int(123)
```

数値の先頭に`0`を付けると8進数として認識され、**`83`**（` (3*1) + (2*8) + (1*64) + (0*512) `）と出力されます。
しかし、文字列で先頭に`0`を付け、integerにキャストして出力すると**`123`**と、**8進数と認識されずにそのまま出力される**ので注意する必要があります。

# おわり

- 何か間違いあれば教えて欲しいです（自分も完全に理解しているわけじゃないので・・・）
- ↑で書いた処理をまとめたやつ置いときます → https://3v4l.org/Wql54

# 参考
- [PHP: 整数 - Manual：整数への変換](https://www.php.net/manual/ja/language.types.integer.php#language.types.integer.casting)
- [float の精度に関する注意](https://www.php.net/manual/ja/language.types.float.php#warn.float-precision)
- [PHP: 整数 - Manual：Converting to an integer works only if the input begins with a number](https://www.php.net/manual/ja/language.types.integer.php#116479)
- [PHP: 文字列 - Manual(文字列の数値への変換)](https://www.php.net/manual/ja/language.types.string.php#language.types.string.conversion)
- [PHP: 整数 - Manual：A leading zero in a numeric literal means "this is octal". But don't be confused: a leading zero in a string does not. ](https://www.php.net/manual/ja/language.types.integer.php#111523)