DynamoDB PHP SDKのMarshalerクラスを使った時にはでかい数値に気をつける
下記のblogで紹介されているように、AWS PHP SDKの 2.7.7 から PHPの型とjsonとDynamoDBの型の相互変換を行うクラス、Marshaler が追加されています。
DynamoDB JSON and Array Marshaling for PHP
この Marshaler クラスを使うと、型変換が行われるため、数値型に大きな値を入れている場合に注意が必要です。
以下に例を示します。
id = 1 のレコードに number = 9223372036854775808 という値が入っているレコードを取り出してみます。
$result = $client->getItem([
'TableName' => 'test_int',
'Key' => ['id' => ['N' => '1']]
]);
var_dump($result['Item']);
結果
array(2) {
["number"]=>
array(1) {
["N"]=>
string(19) "9223372036854775808"
}
["id"]=>
array(1) {
["N"]=>
string(1) "1"
}
}
9223372036854775808 という値が取り出せました。
これを Marshaler でPHPの型に戻してみます。
使用するメソッドは、unmarshalItem です。
use AwsDynamoDbMarshaler;
:
:
$marshaler = new Marshaler();
$data = $marshaler->unmarshalItem($result['Item']);
var_dump($data);
結果
array(2) {
["number"]=>
float(9.2233720368548E+18)
["id"]=>
int(1)
}
9.2233720368548E+18 になってしまいました。/(^o^)\ ナンテコッタイ
原因
PHPでの整数の最大値はPHP_INT_MAXで定められており、9223372036854775807 になっています。(64bitの場合)
それを超えた数字を整数に変換しようとすると、指数表記になってしまいます。
参考:PHP>マニュアル>言語リファレンス>型>整数
一方、DynamoDBの方は、下記ドキュメントにて、最大 38 桁の精度とあるように、 99999999999999999999999999999999999999 まで投入できます。
参考:DynamoDB データモデル
この辺りの相互変換は、言語側の精度に依存する形になると思うので、使っている言語側の仕様を確認しておいた方がよさそうです。
たしか、rubyの場合には BigDecimal に変換されたと思います。