エンジニア

2015.03.02

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 に変換されたと思います。

参考

一覧に戻る