14
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

PHPのjson_encode/json_decodeはそのまま使わない方が良い

Last updated at Posted at 2020-10-26

PHPで配列をJSON形式の文字列に変換する際に利用するjson_encode、またはJSON形式の文字列を配列に変換するjson_decodeの標準関数はそのまま使わないほうが良いと、という投稿です。
PHP玄人の皆さんには常識かと思われますが、意外と知られていない気がしたので共有です。

そのまま使うとどうなるのか

ドキュメントを参照すると次のように説明されています

json_encode

成功した場合に、JSON エンコードされた文字列を返します。 失敗した場合に FALSE を返します。

json_decode

json でエンコードされたデータを、適切な PHP の型として返します。 true、false および null はそれぞれ TRUE、FALSE そして NULL として返されます。 json のデコードに失敗したり エンコードされたデータが再帰制限を超えているなどの場合、NULL を返します。

失敗しても例外にはならず、それぞれfalsenullが返却されます。
これをちゃんとハンドリングして実装していれば問題ないですが、うっかり失敗していたら例外になってくれるんじゃないかと淡い期待をしていると意図しないコードになっている可能性があります。(ちゃんと静的解析してれば問題ないんじゃないですかね)

エラーだった場合、原因が知りたい

エンコード、デコードでエラーがあった場合はjson_last_errorで直近のエラーを調べることができます。
また、json_last_error_msgでエラーメッセージが確認できます。

それ、Guzzleのヘルパー関数が使えるよ

GuzzleといえばPHPでHTTP APIをコールする際にはなくてはならないライブラリ(個人の感想)ですが、このライブラリに用意されているラッパー関数を使うとこの辺のハンドリングが施されています。

\GuzzleHttp\json_encode@7.2.0
function json_encode($value, int $options = 0, int $depth = 512): string
{
    return Utils::jsonEncode($value, $options, $depth);
}

public static function jsonEncode($value, int $options = 0, int $depth = 512): string
{
    $json = \json_encode($value, $options, $depth);
    if (\JSON_ERROR_NONE !== \json_last_error()) {
        throw new InvalidArgumentException('json_encode error: ' . \json_last_error_msg());
    }

    /** @var string */
    return $json;
}
\GuzzleHttp\json_decode@7.2.0
function json_decode(string $json, bool $assoc = false, int $depth = 512, int $options = 0)
{
    return Utils::jsonDecode($json, $assoc, $depth, $options);
}

public static function jsonDecode(string $json, bool $assoc = false, int $depth = 512, int $options = 0)
{
    $data = \json_decode($json, $assoc, $depth, $options);
    if (\JSON_ERROR_NONE !== \json_last_error()) {
        throw new InvalidArgumentException('json_decode error: ' . \json_last_error_msg());
    }

    return $data;
}

失敗していたら例外になってくれるんじゃないか
という淡い期待に答えてくれます。

追記

PHP玄人さんたちが色々教えてくれたので追記

PHP 7.3以降の場合

json_encode/json_decodeのオプションにJSON_THROW_ON_ERRORを指定することでJsonExceptionを発生させることが出来ます。
単純にこれをラップして使うだけでも良さそう。

SafePHPを使う

thecodingmachine/safe
そもそもGuzzleはHTTP APIをコールする際に利用するライブラリなので、こういう専用のライブラリを使うべきですね。こんなライブラリがあるのを知らなかったですw

14
10
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?