在PHP中检查字符串是否为JSON的最快方法?

Fastest way to check if a string is JSON in PHP?

提问人:Kirk Ouimet 提问时间:5/18/2011 最后编辑:Madan SapkotaKirk Ouimet 更新时间:11/24/2023 访问量:557120

问:

我需要一种非常非常快速的方法来检查字符串是否是 JSON。我觉得这不是最好的方法:

function isJson($string) {
    return ((is_string($string) &&
            (is_object(json_decode($string)) ||
            is_array(json_decode($string))))) ? true : false;
}

有没有性能爱好者想要改进这种方法?

php json 错误处理 json-deserialization jsonresult

评论

3赞 5/18/2011
考虑只使用一次...此外,请检查 的输入和返回值。json_decodejson_decode
8赞 Farid Rn 12/7/2012
那么,哪一个是答案呢?
12赞 I wrestled a bear once. 4/10/2015
这里的三元开关是多余的。您的语句已计算为布尔值。
0赞 A.L 1/14/2016
如何确定字符串是否为 JSON 的可能重复项?
1赞 Poonam Bhatt 9/4/2018
接受刘易斯·多诺万(Lewis Donovan)的回答......它工作正常
1赞 Fr0zenFyr 2/20/2019
从解决方案来看,性能与简单性应该是 OP 的主要关注点,因为最快总是取决于用例,例如,如果您知道您将始终处理对象/数组,那么检查字符串的第一个字符就足够了。概括一个解决方案永远不可能是“最快的”;“更快”,可能是。

答:

775赞 Henrik P. Hessel 5/18/2011 #1
function isJson($string) {
   json_decode($string);
   return json_last_error() === JSON_ERROR_NONE;
}

评论

26赞 Kirk Ouimet 5/19/2011
看起来每个人都喜欢这个答案。任何解释为什么?
122赞 Oleg V. Volkov 9/26/2012
当许多传入的字符串预计为非 JSON 时,检查字符串的第一个字符或任何其他文本的第一个符号可能会大大加快此速度。{[
24赞 vee 1/3/2014
$phone = '021234567';var_dump(isJson($phone));返回 true no!它应该返回 false。
28赞 BadHorsie 2/26/2014
请注意,此函数也将为任何数字返回 true,无论您将其指定为字符串还是真数字。 等。因此,这可能是一个有效的 JSON 值,但如果您只想检查带有 或 的有效 JSON 字符串,则该函数的行为可能不符合您的预期6.5 = true, '300' = true, 9 = true{}[];
21赞 zzzzBov 5/8/2015
值得注意的是,这在理论上是正常的。不幸的是,PHP的函数有许多错误,这将允许以奇怪的方式解析无效的JSON。 应该返回,因为不是 JSON,但是应该返回,因为 JSON。似乎有些人没有意识到JSON允许值不仅仅是一个对象或数组。有效的 JSON 值可以是对象、数组、数字、字符串、布尔值和 .json_decodeisJson('0123')false0123isJson('123')true123null
24赞 ahmet alp balkan 5/18/2011 #2
function is_json($str){ 
    return json_decode($str) != null;
}

检测到无效编码时 http://tr.php.net/manual/en/function.json-decode.php 返回值为 null。

评论

0赞 Yoshi 5/18/2011
我认为这个灵魂是:否则应该调用该函数。json_decode($str)!=null;is_not_json
0赞 lonesomeday 5/18/2011
该函数最好重命名为“is other than JSON”!
3赞 zzzzBov 5/8/2015
@user166390,根据规范,json_decode('null') 是有效的 JSON,应返回 的值。null
1赞 Antoine Pinsard 8/13/2015
另请注意,使用此方法,并且将返回,因为类型不会被选中。我认为这种方法应该返回.is_json('false')is_json('[]')false$str === null || json_decode($str) !== null
0赞 ikhvjs 8/11/2021
与此相关的问题 null 是否有效 JSON?.
77赞 mario 5/18/2011 #3

使用json_decode来“探测”它实际上可能不是最快的方法。如果它是一个深度嵌套的结构,那么实例化大量数组对象并将它们扔掉是浪费内存和时间。

因此,使用 preg_matchRFC4627正则表达式来确保有效性可能会更快:

  // in JS:
  var my_JSON_object = !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
         text.replace(/"(\\.|[^"\\])*"/g, '')));

在 PHP 中也是如此:

  return !preg_match('/[^,:{}\\[\\]0-9.\\-+Eaeflnr-u \\n\\r\\t]/',
       preg_replace('/"(\\.|[^"\\\\])*"/', '', $json_string));

然而,没有足够的性能爱好者在这里为基准测试而烦恼。

评论

15赞 mario 6/1/2011
完整的递归正则表达式在这里验证JSON:stackoverflow.com/questions/2583472/regex-to-validate-json/... - 但事实证明,PHP总是比PCRE正则表达式快。(虽然它不是很优化,没有发现综合测试,并且在Perl中的行为可能有所不同。json_decode
3赞 mario 1/3/2014
@vee 是的,谢谢你的笔记。但是让我们把它保留在这里[错误地],所以没有人在生产中真正使用它。
1赞 mario 7/9/2014
@cartbeforehorse好的,谢谢。然后,我修复了PHP双引号字符串上下文的转义。
4赞 cartbeforehorse 7/9/2014
@mario 好的,我明白了。所以基本上,PHP 在 reg-exp 引擎看到它之前就转义了反斜杠。就 reg-exp 引擎而言,字符串中的反斜杠数量是我们人类看到的一半。“就像 reg-exp 还不够复杂”
2赞 Alex Plumb 7/19/2016
我很好奇这是否真的比使用 json_decode 来查看字符串是否是有效的 JSON 更快,所以我运行了一些基准测试。我运行了 100,000 次使用json_encode编码的二维数组。PHP version : 5.5.34 Platform : Darwin -------------------------------------- test_json_decode : 5.608 sec. test_regex : 10.428 sec.
104赞 user1653711 9/7/2012 #4

你真正需要做的就是这个......

if (is_object(json_decode($MyJSONArray))) 
{ 
    ... do something ...
}

此请求甚至不需要单独的功能。只需is_object缠绕json_decode,然后继续前进。似乎这个解决方案让人们花了太多心思。

评论

3赞 userabuser 2/14/2014
@RomanM.Kos 需要明确的是,如果数组是一个简单的数组,那么除了 之外,还需要使用 ,否则对于编码为 JSON 的简单数组将返回 false。所以在这种情况下@ggutenberg是对的。传递 true 参数强制将对象作为数组返回。从理论上讲,您始终可以强制解码到数组并检查 ,这应该可以工作。is_arrayis_objectis_objectjson_decodeis_array
0赞 Roman M. Koss 2/15/2014
@userabuser 如果 i 为简单的 PHP 数组,然后 do i 将接收对象,但不会接收数组。 强制转换为数组。为什么你的代码中有复杂的字符串?检查一下,一段时间后,当你阅读它时,你会明白解码的一定只是一个数组。更难猜到“哦,我在这里检查解码是否是一个数组?json_encode($array)json_decode($str)json_decode($str, true)is_array(json_decode($str, true))is_object(json_decode($MyJSONArray))
0赞 userabuser 2/15/2014
@RomanM.Kos 不,这是不正确的,codepad.viper-7.com/OFrtsq - 正如我所说,你总是可以强制返回一个数组,以节省你检查对象和数组的时间,但如果你不这样做,你一开始是一个简单的数组,你将在解码时收到一个数组作为回报,而不是一个对象。如果要始终强制对象进行编码 IF 传递简单数组,则必须使用。json_decodejson_decodeJSON_FORCE_OBJECT
29赞 cartbeforehorse 7/9/2014
投反对票说:.严格来说,没有任何解决方案需要单独的功能。函数的重点不是使多行代码看起来像一行代码。该函数的重点是使 JSON 检查过程在应用程序中的任何地方都成为标准,以便不同的程序员(或随着时间的推移的同一程序员)不会在程序流的不同阶段使用不同的检查过程。This request does not require a separate function even
1赞 maxpower9000 2/14/2013 #5

我不知道我的解决方案的性能或优雅,但这就是我正在使用的:

if (preg_match('/^[\[\{]\"/', $string)) {
    $aJson = json_decode($string, true);
    if (!is_null($aJson)) {
       ... do stuff here ...
    }
}

由于我所有 JSON 编码的字符串都以 {“ 开头,因此使用正则表达式测试这一点就足够了。我对正则表达式一点也不流利,所以可能有更好的方法可以做到这一点。另外:strpos() 可能会更快。

只是想放弃我的傻瓜价值。

PS 刚刚更新了正则表达式字符串以查找 JSON 数组字符串。因此,它现在在字符串的开头查找 [“ 或 {”。/^[\[\{]\"/

235赞 Madan Sapkota 3/4/2013 #6

问题的答案

该函数返回 JSON 编码和解码期间发生的最后一个错误。因此,检查有效 JSON 的最快方法是json_last_error

// decode the JSON data
// set second parameter boolean TRUE for associative array output.
$result = json_decode($json);

if (json_last_error() === JSON_ERROR_NONE) {
    // JSON is valid
}

// OR this is equivalent

if (json_last_error() === 0) {
    // JSON is valid
}

请注意,仅在 PHP >= 5.3.0 中受支持。json_last_error

检查确切错误的完整程序

在开发过程中了解确切的错误总是好的。这是根据PHP文档检查确切错误的完整程序。

function json_validate($string)
{
    // decode the JSON data
    $result = json_decode($string);

    // switch and check possible JSON errors
    switch (json_last_error()) {
        case JSON_ERROR_NONE:
            $error = ''; // JSON is valid // No error has occurred
            break;
        case JSON_ERROR_DEPTH:
            $error = 'The maximum stack depth has been exceeded.';
            break;
        case JSON_ERROR_STATE_MISMATCH:
            $error = 'Invalid or malformed JSON.';
            break;
        case JSON_ERROR_CTRL_CHAR:
            $error = 'Control character error, possibly incorrectly encoded.';
            break;
        case JSON_ERROR_SYNTAX:
            $error = 'Syntax error, malformed JSON.';
            break;
        // PHP >= 5.3.3
        case JSON_ERROR_UTF8:
            $error = 'Malformed UTF-8 characters, possibly incorrectly encoded.';
            break;
        // PHP >= 5.5.0
        case JSON_ERROR_RECURSION:
            $error = 'One or more recursive references in the value to be encoded.';
            break;
        // PHP >= 5.5.0
        case JSON_ERROR_INF_OR_NAN:
            $error = 'One or more NAN or INF values in the value to be encoded.';
            break;
        case JSON_ERROR_UNSUPPORTED_TYPE:
            $error = 'A value of a type that cannot be encoded was given.';
            break;
        default:
            $error = 'Unknown JSON error occured.';
            break;
    }

    if ($error !== '') {
        // throw the Exception or exit // or whatever :)
        exit($error);
    }

    // everything is OK
    return $result;
}

使用有效的 JSON INPUT 进行测试

$json = '[{"user_id":13,"username":"stack"},{"user_id":14,"username":"over"}]';
$output = json_validate($json);
print_r($output);

有效输出

Array
(
    [0] => stdClass Object
        (
            [user_id] => 13
            [username] => stack
        )

    [1] => stdClass Object
        (
            [user_id] => 14
            [username] => over
        )
)

使用无效的 JSON 进行测试

$json = '{background-color:yellow;color:#000;padding:10px;width:650px;}';
$output = json_validate($json);
print_r($output);

无效的输出

Syntax error, malformed JSON.

(PHP >= 5.2 && PHP < 5.3.0)的额外说明

由于 PHP 5.2 不支持,因此可以检查编码或解码是否返回 boolean 。下面是一个示例json_last_errorFALSE

// decode the JSON data
$result = json_decode($json);
if ($result === FALSE) {
    // JSON is invalid
}

评论

0赞 Bruno 12/20/2016
小精度 :如果这个 JSON 有效,但之前解码的 JSON 无效,你的代码将正常工作,因为:“返回上次 JSON 编码/解码期间发生的最后一个错误(如果有)。"
0赞 Francis Rodrigues 2/25/2017
感谢@Madan,“json_decode”验证解决了我运行 PHP 7.0 的问题。
1赞 MrMesees 7/11/2017
当然,json_decode可以为字面上的 false 返回 false,因此也应该进行检查以避免该边缘?((strlen($json) === 5) && ($json !== 'false'))
0赞 Andrea 2/14/2018
@Bruno 如果上次解码没有错误,则返回 .json_last_errorJSON_ERROR_NONE
27赞 upful 10/21/2013 #7

PHP 8.3 (英语)

原生 PHP 函数

json_validate(string $json, int $depth = 512, int $flags = 0): bool

https://wiki.php.net/rfc/json_validate

PHP < 8.3

提供与上述结果类似的方法json_validate()

function is_json($string) {
  return is_numeric($string)
    || in_array($string, ['null', 'true', 'false']
    || ( is_bool($string) && $string )
    || (
      !empty($string) 
      && is_string($string) 
      && is_array(json_decode($string, true)) 
      && json_last_error() === JSON_ERROR_NONE
    );
}

有时,查看 JSON 对象是否包含数据(对象或数组)会很有帮助

function has_json_data($string) {
  return !empty($string) 
    && is_string($string) 
    && is_array($array = json_decode($string, true)) 
    && !empty($array) 
    && json_last_error() === JSON_ERROR_NONE;
}

评论

0赞 cartbeforehorse 7/9/2014
+1 表示在现实世界中实际思考问题。
0赞 upful 12/6/2014
但不是有效的 json...我为什么要保持警惕?@Kzqai'0'
0赞 Harsh Patel 12/14/2021
if(is_string($string) && is_array(json_decode($string, true)) && (json_last_error() == JSON_ERROR_NONE)){ // json is valid }else{ // not valid }
0赞 Harsh Patel 12/14/2021
请参阅此博客文章 subinsb.com/php-check-if-string-is-json
3赞 Asad Ali 6/26/2023
截至 2023 年 6 月,json_validate() 正式成为 PHP 8.3 Alpha-2 版本的一部分。
1赞 miken32 12/3/2023
@upful裸数是有效的 JSON,值 、 和 .而且,永远不应该使用固定值来代替常量。truefalsenull
3赞 h0mayun 2/8/2014 #8

另一种简单的方法

function is_json($str)
{
    return is_array(json_decode($str,true));
}

评论

1赞 Chaoix 8/16/2014
这是不正确的。任何 PHP 类型都可以编码为 JSON,例如对象、字符串等,并且 json_decode 函数应该返回它们。仅当您始终解码数组而没有其他变量类型时,这才是正确的。
0赞 Paul Phillips 3/18/2015
@Chaoix使用使它将对象转换为数组,因此它将通过is_array检查。不过,您纠正了字符串、整数等。json_decode($str,true)
0赞 Chaoix 3/27/2015
我明白你对json_encode上第二个参数的意思。我仍然认为@Ahad Ali 的解决方案在打字方面要好得多,并且在您的算法中只做一次json_decode。
5赞 Ahad Ali 6/27/2014 #9

早些时候我只是检查一个空值,这实际上是错误的。

    $data = "ahad";
    $r_data = json_decode($data);
    if($r_data){//json_decode will return null, which is the behavior we expect
        //success
    }

上面的一段代码适用于字符串。但是,一旦我提供号码,它就会破裂。

    $data = "1213145";
    $r_data = json_decode($data);

    if($r_data){//json_decode will return 1213145, which is the behavior we don't expect
        //success
    }

为了解决这个问题,我所做的非常简单。

    $data = "ahad";
    $r_data = json_decode($data);

    if(($r_data != $data) && $r_data)
        print "Json success";
    else
        print "Json error";

评论

0赞 Chaoix 8/16/2014
不错的解决方案。很好地处理了打字问题!
29赞 Mohammad Mursaleen 8/28/2014 #10

我使用的最简单、最快的方法是遵循;

$json_array = json_decode( $raw_json , true );

if( $json_array == NULL )   //check if it was invalid json string
    die ('Invalid');  // Invalid JSON error

 // you can execute some else condition over here in case of valid JSON

这是因为如果输入的字符串不是 json 或无效的 json,则 json_decode() 返回 NULL。


验证JSON的简单函数

如果必须在多个位置验证 JSON,则始终可以使用以下函数。

function is_valid_json( $raw_json ){
    return ( json_decode( $raw_json , true ) == NULL ) ? false : true ; // Yes! thats it.
}

在上面的函数中,如果它是有效的 JSON,您将得到 true 作为回报。

评论

4赞 zzzzBov 5/8/2015
json_decode('null') == NULL并且是有效的 JSON 值。null
0赞 Mohammad Mursaleen 5/24/2015
我已经测试了“null”是否在 json.parser.online 上是有效的 json,但似乎它不是有效的 json。json_decode() 是验证 json 的 php 核心函数,所以我怀疑在我们的输出中得到一些错误的结果。
3赞 zzzzBov 5/24/2015
与其相信一些未经验证的网站,不如考虑咨询不同意的规范(第 2 页)。或者,在开发控制台中尝试。JSON.parse('null')
1赞 ikhvjs 8/11/2021
与此相关的问题 null 是否有效 JSON?.
-2赞 biziclop 5/26/2015 #11

PHP 5.2 兼容性的新函数,如果您需要成功解码的数据:

function try_json_decode( $json, & $success = null ){
  // non-strings may cause warnings
  if( !is_string( $json )){
    $success = false;
    return $json;
  }

  $data = json_decode( $json );

  // output arg
  $success =

    // non-null data: success!
    $data !==  null  ||

    // null data from 'null' json: success!
    $json === 'null' ||

    // null data from '  null  ' json padded with whitespaces: success!
    preg_match('/^\s*null\s*$/', $json );

  // return decoded or original data
  return $success ? $data : $json;
}

用法:

$json_or_not = ...;

$data = try_json_decode( $json_or_not, $success );

if( $success )
     process_data( $data );
else what_the_hell_is_it( $data );

一些测试:

var_dump( try_json_decode( array(), $success ), $success );
// ret = array(0){}, $success == bool(false)

var_dump( try_json_decode( 123, $success ), $success );
// ret = int(123), $success == bool(false)

var_dump( try_json_decode('      ', $success ), $success );
// ret = string(6) "      ", $success == bool(false)

var_dump( try_json_decode( null, $success ), $success );
// ret = NULL, $success == bool(false)

var_dump( try_json_decode('null', $success ), $success );
// ret = NULL, $success == bool(true)

var_dump( try_json_decode('  null  ', $success ), $success );
// ret = NULL, $success == bool(true)

var_dump( try_json_decode('  true  ', $success ), $success );
// ret = bool(true), $success == bool(true)

var_dump( try_json_decode('  "hello"  ', $success ), $success );
// ret = string(5) "hello", $success == bool(true)

var_dump( try_json_decode('  {"a":123}  ', $success ), $success );
// ret = object(stdClass)#2 (1) { ["a"]=> int(123) }, $success == bool(true)
0赞 Robert Johnstone 6/9/2015 #12

扩展这个答案 以下几点怎么样:

<?php

    $json = '[{"user_id":13,"username":"stack"},{"user_id":14,"username":"over"}]';
    //$json = '12';

    function isJson($string) {
        json_decode($string);
        if(json_last_error() == JSON_ERROR_NONE) {
            if(substr($string,0,1) == '[' && substr($string,-1) == ']') { return TRUE; }
            else if(substr($string,0,1) == '{' && substr($string,-1) == '}') { return TRUE; }
            else { return FALSE; }
        }
    }

    echo isJson($json);
?>

评论

3赞 Mark 8/7/2015
如果在检查中发现错误,难道不应该在执行解码之前进行子字符串检查以节省时间吗?我想 4 个子字符串检查会比一个json_decode更快,但如果有人能用这个假设来支持我,我将不胜感激。
0赞 Robert Johnstone 8/17/2015
这是一个票价论点。我不知道涉及的处理时间,但如果它更快,那么是的。
5赞 Sergey Onishchenko 5/11/2016 #13

我们需要检查传递的字符串是否不是数字,因为在这种情况下json_decode不会引发错误。

function isJson($str) {
    $result = false;
    if (!preg_match("/^\d+$/", trim($str))) {
        json_decode($str);
        $result = (json_last_error() == JSON_ERROR_NONE);
    }

    return $result;
}
9赞 Rameez Rami 9/29/2016 #14

简单的方法是检查json结果。

$result = @json_decode($json,true);
    if (is_array($result)) {
        echo 'JSON is valid';
    }else{
        echo 'JSON is not valid';
    }
6赞 Parsa 12/20/2016 #15

GuzzleHttp 中:

/**
 * Wrapper for json_decode that throws when an error occurs.
 *
 * @param string $json    JSON data to parse
 * @param bool $assoc     When true, returned objects will be converted
 *                        into associative arrays.
 * @param int    $depth   User specified recursion depth.
 * @param int    $options Bitmask of JSON decode options.
 *
 * @return mixed
 * @throws \InvalidArgumentException if the JSON cannot be decoded.
 * @link http://www.php.net/manual/en/function.json-decode.php
 */
function json_decode($json, $assoc = false, $depth = 512, $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;
}

/**
 * Wrapper for JSON encoding that throws when an error occurs.
 *
 * @param mixed $value   The value being encoded
 * @param int    $options JSON encode option bitmask
 * @param int    $depth   Set the maximum depth. Must be greater than zero.
 *
 * @return string
 * @throws \InvalidArgumentException if the JSON cannot be encoded.
 * @link http://www.php.net/manual/en/function.json-encode.php
 */
function json_encode($value, $options = 0, $depth = 512)
{
    $json = \json_encode($value, $options, $depth);
    if (JSON_ERROR_NONE !== json_last_error()) {
        throw new \InvalidArgumentException(
            'json_encode error: ' . json_last_error_msg());
    }

    return $json;
}
71赞 Cyril 4/6/2017 #16

如果你的字符串表示一个 json 数组或对象,这将返回 true

function isJson($str) {
    $json = json_decode($str);
    return $json && $str != $json;
}

它拒绝仅包含数字、字符串或布尔值的 json 字符串,尽管这些字符串在技术上是有效的 json。

var_dump(isJson('{"a":5}')); // bool(true)
var_dump(isJson('[1,2,3]')); // bool(true)
var_dump(isJson('1')); // bool(false)
var_dump(isJson('1.5')); // bool(false)
var_dump(isJson('true')); // bool(false)
var_dump(isJson('false')); // bool(false)
var_dump(isJson('null')); // bool(false)
var_dump(isJson('hello')); // bool(false)
var_dump(isJson('')); // bool(false)

这是我能想到的最短的方法。

评论

0赞 MrMesees 7/11/2017
与其var_dump,不如把它放在 PHPUnit 测试用例中。否则,我既惊讶又高兴地得知这是真的。
4赞 toddmo 5/14/2018
为什么其他人都有这么长的答案,而这很好用?谢谢。
2赞 Fr0zenFyr 2/20/2019
简单来说,很可爱!没有检查“最快的方法”或性能方面,但这个肯定涵盖了我曾经检查过的所有情况。这是臭名昭著的谚语“不要用大锤敲坚果”的经典例子。从程序员的角度来看,保持代码简单、简短和易于理解总是更好的,性能与简单性是这个线程范围之外的另一个争论。
1赞 Cyril 10/11/2019
@j13k 相同的比较的计算结果为 true,这不是有效的 json。这里特意选择松散的比较。对于空数组/对象情况,我没有快速解决方案,除了丑陋的isJson('hello')return $json == '[]' || ...
3赞 j13k 10/14/2019
@Cyril,很抱歉,我错过了这种情况,因为我的测试函数包括额外的检查,以便在调用之前使函数短路。由于 'hello' 字符串会触发 JSON 错误,因此该函数的输出为 ,因此额外的检查足以使用测试数据生成正确的结果:json_decodeNULL!is_nullreturn $json !== false && !is_null($json) && $str != $json;
32赞 Philipp 7/21/2017 #17

在尝试解码 JSON 字符串之前,我们首先执行一些类型检查和字符串比较。这为我们提供了最佳性能,因为速度可能很慢。json_decode()

/**
 * Returns true, when the given parameter is a valid JSON string.
 */
function is_json( $value ) {
    // Numeric strings are always valid JSON.
    if ( is_numeric( $value ) ) { return true; }

    // A non-string value can never be a JSON string.
    if ( ! is_string( $value ) ) { return false; }

    // Any non-numeric JSON string must be longer than 2 characters.
    if ( strlen( $value ) < 2 ) { return false; }

    // "null" is valid JSON string.
    if ( 'null' === $value ) { return true; }

    // "true" and "false" are valid JSON strings.
    if ( 'true' === $value ) { return true; }
    if ( 'false' === $value ) { return true; }

    // Any other JSON string has to be wrapped in {}, [] or "".
    if ( '{' != $value[0] && '[' != $value[0] && '"' != $value[0] ) { return false; }

    // Verify that the trailing character matches the first character.
    $last_char = $value[strlen($value) -1];
    if ( '{' == $value[0] && '}' != $last_char ) { return false; }
    if ( '[' == $value[0] && ']' != $last_char ) { return false; }
    if ( '"' == $value[0] && '"' != $last_char ) { return false; }

    // See if the string contents are valid JSON.
    return null !== json_decode( $value );
}

额外:使用此逻辑安全地对 JSON 进行双重解码

此函数使用相同的逻辑,但返回解码的 JSON 对象原始值

我在递归解码复杂对象的解析器中使用此函数。某些属性可能已由早期迭代解码。该函数会识别这一点,并且不会尝试再次对值进行双重解码。

/**
 * Tests, if the given $value parameter is a JSON string.
 * When it is a valid JSON value, the decoded value is returned.
 * When the value is no JSON value (i.e. it was decoded already), then 
 * the original value is returned.
 */
function get_data( $value, $as_object = false ) {
    if ( is_numeric( $value ) ) { return 0 + $value; }
    if ( ! is_string( $value ) ) { return $value; }
    if ( strlen( $value ) < 2 ) { return $value; }
    if ( 'null' === $value ) { return null; }
    if ( 'true' === $value ) { return true; }
    if ( 'false' === $value ) { return false; }
    if ( '{' != $value[0] && '[' != $value[0] && '"' != $value[0] ) { return $value; }

    $json_data = json_decode( $value, $as_object );
    if ( is_null( $json_data ) ) { return $value; }
    return $json_data;
}

注意:当将非字符串传递给此 SO 问题中的任何其他解决方案时,您将获得性能显着下降 + 错误的返回值(甚至是致命错误)。此代码是无懈可击且高性能的。

评论

1赞 Philipp 2/6/2021
我不确定,为什么这个答案被否决了,甚至有删除请求。我的性能测试清楚地表明,这是迄今为止最快的方法。以下是性能比较脚本:gist.github.com/stracker-phil/6a80e6faedea8dab090b4bf6668ee461
1赞 Enigma Plus 6/11/2021
+1 表示纯粹的努力:)我认为令人惊讶的是,当您的测试实际上有 8 个“if”语句时,它实际上更快。我想人们不会喜欢它,因为它一点也不优雅,而且除非你需要检查大约一百万位的文本,否则它真的没有太大的开销差异。
2赞 Philipp 6/11/2021
@EnigmaPlus谢谢:)没错,代码不是优雅的单行代码,但问题在于找到最快的方法,而不是最优雅/最短的方法。 更短,但需要 PHP 初始化一个内部 JSON 解析器实例,该实例相当复杂,比 8 个简单 s 😉 慢得多json_decodeif
1赞 Eric P 1/3/2022
您的 $json_data = json_decode($value,null,1) 示例;计算时返回 NULL,如 '{“a”:5}' 或 '[1,2,3]'。应该有两个级别,例如:json_decode($value,null,2);
1赞 Eric P 1/3/2022
is_numeric($value)应作为第一评价。
2赞 Greco Jonathan 10/6/2017 #18

我已经尝试了一些解决方案,但没有任何效果。我尝试这个简单的事情:

$isJson = json_decode($myJSON);

if ($isJson instanceof \stdClass || is_array($isJson)) {
   echo("it's JSON confirmed");
} else {
   echo("nope");
}

我认为这是一个很好的解决方案,因为没有第二个参数的 JSON 解码会给出一个对象。

编辑:如果您知道输入的内容,则可以根据需要调整此代码。就我而言,我知道我有一个以“{”开头的 Json,所以我不需要检查它是否是一个数组。

评论

0赞 Misha Nasledov 2/14/2018
你的 JSON 可能只是一个数组,在这种情况下,它将是一个数组,而不是 stdClass $foo = “[1, 1, 2, 3]”;var_dump(json_decode($foo));=> array(4) { [0]=> int(1) [1]=> int(1) [2]=> int(2) [3]=> int(3) }
2赞 Tinh Dang 4/9/2018 #19

应该是这样的:

 function isJson($string)
 {
    // 1. Speed up the checking & prevent exception throw when non string is passed
    if (is_numeric($string) ||
        !is_string($string) ||
        !$string) {
        return false;
    }

    $cleaned_str = trim($string);
    if (!$cleaned_str || !in_array($cleaned_str[0], ['{', '['])) {
        return false;
    }

    // 2. Actual checking
    $str = json_decode($string);
    return (json_last_error() == JSON_ERROR_NONE) && $str && $str != $string;
}

单元测试

public function testIsJson()
{
    $non_json_values = [
        "12",
        0,
        1,
        12,
        -1,
        '',
        null,
        0.1,
        '.',
        "''",
        true,
        false,
        [],
        '""',
        '[]',
        '   {',
        '   [',
    ];

   $json_values = [
        '{}',
        '{"foo": "bar"}',
        '[{}]',
        '  {}',
        ' {}  '
    ];

   foreach ($non_json_values as $non_json_value) {
        $is_json = isJson($non_json_value);
        $this->assertFalse($is_json);
    }

    foreach ($json_values as $json_value) {
        $is_json = isJson($json_value);
        $this->assertTrue($is_json);
    }
}

评论

0赞 sykez 1/3/2020
我喜欢你检查它是否是一个字符串。与第一个解决方案结合使用,以避免字符串是数组或对象。ErrorException
0赞 Neo 1/23/2023
我很高兴您可以编写代码来加速内部 ph 函数。我想我的电脑在尝试json_decode一个数字时崩溃了。这 200 行代码绝对是更少的汇编代码。你能用 0 和 1 写代码吗?我只是在和你开玩笑,我的朋友。我以笑话的形式提出的论点是,你真的认为并基准测试了所有这些代码比内部用 C 语言编写的 Php(一个较低级别的程序)更快吗?这个函数有各种各样的断点,你实际上是在浪费更多的人类时间,担心你在数学上所说的CPU时间,只有在它有任何区别时才会增加。
0赞 Neo 1/23/2023
我去帮你找到了源代码:github.com/php/php-src/blob/master/ext/json/json.c
0赞 Tinh Dang 1/24/2023
该函数本身只有 18 行代码。即使包括 unittest,它也只有大约 60 行。我敢肯定你是个小丑。第二,它纯粹是用PHP编写的,以解决我们在这里遇到的问题,它也很容易理解和实现。我敢肯定每次调用该函数只需要以毫秒为单位的时间。第三,除非你能在PHP中给出一些更好的解决方案,否则请这样做,否则在这里提到C是不合适的,或者你只是炫耀你的C技能先生?
0赞 Tinh Dang 1/24/2023
看到有人将 5 年前给出的解决方案与最近在 PHP 8.3 中添加的函数(几个月前)进行比较,该函数是用 C 编写的,直接在 PHP 核心中实现,然后谈论无意义的话题,这真是太奇怪了。无论如何,请去添加一个新的答案,不要忘记提到从 8.3 开始,我们可以使用json_validate并使用您在那里的某种形式的笑话来为世界带来欢乐。
14赞 Lewis Donovan 8/1/2018 #20

这将完成:

function isJson($string) {
    $decoded = json_decode($string); // decode our JSON string
    if ( !is_object($decoded) && !is_array($decoded) ) {
        /*
        If our string doesn't produce an object or array
        it's invalid, so we should return false
        */
        return false;
    }
    /*
    If the following line resolves to true, then there was
    no error and our JSON is valid, so we return true.
    Otherwise it isn't, so we return false.
    */
    return (json_last_error() == JSON_ERROR_NONE);
}

if ( isJson($someJsonString) ) {
    echo "valid JSON";
} else {
    echo "not valid JSON";
}

如其他答案所示,json_last_error() 返回上一个 json_decode() 中的任何错误。但是,在某些边缘用例中,仅此功能本身还不够全面。例如,如果您json_decode()一个整数(例如:),或一个没有空格或其他字符(例如:)的数字字符串,则该函数不会捕获错误。123"123"json_last_error()

为了解决这个问题,我添加了一个额外的步骤,以确保我们的结果是对象或数组。如果不是,那么我们返回.json_decode()false

若要查看此操作,请查看以下两个示例:

评论

1赞 JoniJnm 8/13/2019
"hello"是一个有效的 JSON,它既不是对象也不是数组,就足够了json_last_error()
1赞 Lewis Donovan 8/15/2019
json_last_error()当您将字符串 .示例如下:3v4l.org/lSsEo4json_decode()"hello"
1赞 JoniJnm 9/6/2019
您的代码是错误的,不是有效的 JSON,但 3v4l.org/OEJrQhello"hello"
0赞 miken32 12/3/2023
、 、 等相同。所有有效的 json。false46783null
2赞 Jack 12/5/2018 #21

嗨,这是我库中的一个小片段,在第一种情况下,我只是检查数据是否是 json,然后在正确解码时返回它,请注意性能的子 str 用法( 我还没有看到任何 json 文件不是以 { 或 [ 开头的

$input=trim($input);
if ((substr($input, 0, 1) == '{' && substr($input, -1) == '}') or (substr($input, 0, 1) == '[' && substr($input, -1) == ']')) {
    $output = json_decode($input, 1);
    if (in_array(gettype($output),['object','array'])) {
        #then it's definitely JSON
    }
}

评论

0赞 miken32 12/5/2018
这个问题已经有 34 个答案,其中许多也赞同(错误的)信念,即 JSON 必须表示数组或对象。这个答案与其他 3 打答案有什么不同吗?
1赞 Oliver M Grech 10/10/2021
我相信这个答案有很多好处,对于大多数用例,我们已经知道我们期待一个 json 字符串,所以这是检查大括号,所以如果找不到它们,就不需要json_decode。+1 来自我。
0赞 kalicki2k 6/5/2019 #22

我的另一个建议:)

function isJson(string $string) {
  return ($result = json_decode($string, true)) ? $result : $string;
}
0赞 user11487450 1/20/2020 #23

这是我创建的一个高性能且简单的函数(在用于较大的字符串之前使用基本的字符串验证):json_decode

function isJson($string) {
    $response = false;

    if (
        is_string($string) &&
        ($string = trim($string)) &&
        ($stringLength = strlen($string)) &&
        (
            (
                stripos($string, '{') === 0 &&
                (stripos($string, '}', -1) + 1) === $stringLength
            ) ||
            (
                stripos($string, '[{') === 0 &&
                (stripos($string, '}]', -1) + 2) === $stringLength
            )
        ) &&
        ($decodedString = json_decode($string, true)) &&
        is_array($decodedString)
    ) {
        $response = true;
    }

    return $response;
}
13赞 Matthew Anderson 1/22/2020 #24

将 PHPBench 与以下类一起使用,可以获得以下结果:

<?php

declare(strict_types=1);

/**
 * @Revs(1000)
 * @Iterations(100)
 */
class BenchmarkJson
{
    public function benchCatchValid(): bool
    {
        $validJson = '{"validJson":true}';
        try {
            json_decode($validJson, true, 512, JSON_THROW_ON_ERROR);
            return true;
        } catch(\JsonException $exception) {}
        return false;
    }

    public function benchCatchInvalid(): bool
    {
        $invalidJson = '{"invalidJson"';
        try {
            json_decode($invalidJson, true, 512, JSON_THROW_ON_ERROR);
            return true;
        } catch(\JsonException $exception) {}
        return false;
    }

    public function benchLastErrorValid(): bool
    {
        $validJson = '{"validJson":true}';
        json_decode($validJson, true);
        return (json_last_error() === JSON_ERROR_NONE);
    }

    public function benchLastErrorInvalid(): bool
    {
        $invalidJson = '{"invalidJson"';
        json_decode($invalidJson, true);
        return (json_last_error() === JSON_ERROR_NONE);
    }

    public function benchNullValid(): bool
    {
        $validJson = '{"validJson":true}';
        return (json_decode($validJson, true) !== null);
    }

    public function benchNullInvalid(): bool
    {
        $invalidJson = '{"invalidJson"';
        return (json_decode($invalidJson, true) !== null);
    }
}

6 subjects, 600 iterations, 6,000 revs, 0 rejects, 0 failures, 0 warnings
(best [mean mode] worst) = 0.714 [1.203 1.175] 1.073 (μs)
⅀T: 721.504μs μSD/r 0.089μs μRSD/r: 7.270%
suite: 1343ab9a3590de6065bc0bc6eeb344c9f6eba642, date: 2020-01-21, stime: 12:50:14
+---------------+-----------------------+-----+------+-----+------------+---------+---------+---------+---------+---------+--------+-------+
| benchmark     | subject               | set | revs | its | mem_peak   | best    | mean    | mode    | worst   | stdev   | rstdev | diff  |
+---------------+-----------------------+-----+------+-----+------------+---------+---------+---------+---------+---------+--------+-------+
| BenchmarkJson | benchCatchValid       | 0   | 1000 | 100 | 2,980,168b | 0.954μs | 1.032μs | 1.016μs | 1.428μs | 0.062μs | 6.04%  | 1.33x |
| BenchmarkJson | benchCatchInvalid     | 0   | 1000 | 100 | 2,980,184b | 2.033μs | 2.228μs | 2.166μs | 3.001μs | 0.168μs | 7.55%  | 2.88x |
| BenchmarkJson | benchLastErrorValid   | 0   | 1000 | 100 | 2,980,184b | 1.076μs | 1.195μs | 1.169μs | 1.616μs | 0.083μs | 6.97%  | 1.54x |
| BenchmarkJson | benchLastErrorInvalid | 0   | 1000 | 100 | 2,980,184b | 0.785μs | 0.861μs | 0.863μs | 1.132μs | 0.056μs | 6.54%  | 1.11x |
| BenchmarkJson | benchNullValid        | 0   | 1000 | 100 | 2,980,168b | 0.985μs | 1.124μs | 1.077μs | 1.731μs | 0.114μs | 10.15% | 1.45x |
| BenchmarkJson | benchNullInvalid      | 0   | 1000 | 100 | 2,980,184b | 0.714μs | 0.775μs | 0.759μs | 1.073μs | 0.049μs | 6.36%  | 1.00x |
+---------------+-----------------------+-----+------+-----+------------+---------+---------+---------+---------+---------+--------+-------+

结论:检查json是否有效的最快方法是返回。json_decode($json, true) !== null)

评论

0赞 Mahdi 2/19/2020
非常好:)我很佩服你
16赞 Rounin 1/23/2020 #25

昨天,我在工作中遇到类似的事情后发现了这个问题。最后,我的解决方案是上述一些方法的混合体:

function is_JSON($string) {

  return (is_null(json_decode($string))) ? FALSE : TRUE;
}

评论

1赞 Ricardo Martins 6/25/2020
我也不习惯了,呵呵。由于我使用的 PhpStorm 和 Magento 代码嗅探器工具总是抱怨我,所以我开始采用这种方法。最后,我们得到了更干净的代码并习惯了它。:P
2赞 ikhvjs 8/11/2021
与此相关的问题 null 是否有效 JSON?.
0赞 Rounin 8/11/2021
谢谢你的提醒,@ikhvjs。如果要预测这种情况,可以在上述函数的内容前面加上以下条件:if (is_null($string)) return TRUE;
2赞 hanshenrik 7/23/2022
is_null已经返回布尔,可以缩短为return is_null(json_decode($string));
0赞 berend 2/17/2023
可能与函数的名称更一致,人们希望返回有效的JSON格式...所以:true$stringreturn !is_null(json_decode($string));
6赞 user11995521 2/1/2020 #26
//Tested thoroughly, Should do the job:
public static function is_json(string $json):bool
{
    json_decode($json);
    if (json_last_error() === JSON_ERROR_NONE) {
        return true;
    }
    return false;
}
0赞 user10012 8/28/2020 #27

这是我推荐的

if (!in_array(substr($string, 0, 1), ['{', '[']) || !in_array(substr($string, -1), ['}', ']'])) {
  return false;
} else {
  json_decode($string);
  return (json_last_error() === JSON_ERROR_NONE);
}

评论

0赞 miken32 12/3/2023
以下是有效的 JSON 字符串,不会通过检查:、、2352"foo"null
1赞 milad nazari 7/13/2021 #28
function isJson($string) {
    $obj = json_decode($string);
    return json_last_error() === JSON_ERROR_NONE && gettype($obj ) == "object";
}

这有效,并且不会对数字返回 true

最新更新

如果JSON很长,并且不需要使用$obj,则上述解决方案的性能不佳

如果你只是想检查,最好使用下面的功能

function isJson($string) {
    if(is_numeric($string)) return false;
    json_decode($string);
    return json_last_error() === JSON_ERROR_NONE;
}

评论

1赞 Dennis Richter 9/24/2021
恕我直言,如果您还想实际使用解码的对象,这是最好的解决方案,应该是 json
0赞 milad nazari 9/29/2021
你是对的。我更新了答案
0赞 miken32 12/3/2023
数字是有效的 JSON。
1赞 jcmargentina 8/25/2022 #29

更新:json_validate() 将在 PHP 8.3 中上线

仅供参考:

我正在研究一个 RFC,以在 php 中添加一个新函数,该函数能够仅验证 json 字符串,而无需在此过程中生成对象/数组。

为什么使用仅验证函数?因为 json_decode() 在解析 json-string 时会创建一个数组/对象,从而影响正在使用的内存量;这意味着在验证 JSON 字符串时可以达到最大内存限制。

为了给你一个想法,请检查以下代码 performance_test_json_validate()_vs_json_decode()

在该测试中,我们可以看到新函数 json_validate() 使用 0 MB 来验证 json-string,而 json_decode() 需要 109 MB 来执行此操作(因为它在解析时会创建一个内存中的数组/对象。

目前这是正在进行的工作,但我发布这个是因为我对你的意见感兴趣(不是你认为是否值得拥有它,我的意思是,从技术角度来看)。

Github:https://github.com/php/php-src/pull/9399

RFC(工作进行中):https://wiki.php.net/rfc/json_validate

期待您对此的意见/支持。

提前致谢。

6赞 jcmargentina 10/10/2022 #30

json_validate() 函数的 RFC 已经实现,并将成为 PHP 8.3 的一部分

这种方法将是实现问题要求的最快和最有效的方法。

GitHub - 实现代码

RFC - 的 json_validate()

评论

0赞 miken32 12/3/2023
也许您想编辑这个问题,因为 8.3 已经发布并且有该函数的文档。
6赞 Ion Bazan 1/6/2023 #31

虽然仍在开发中的PHP 8.3将具有新的内存效率功能,但由于Symfony Polyfill组件的出色表现,您可以将其与较旧的PHP版本(7.1及更新版本)一起使用。json_validate()

只需将以下包添加到您的项目中:

composer require symfony/polyfill-php83

并在您的应用程序中使用它:

if (json_validate($data)) {
  // do sometihng
}

由于这种方法,您可以在旧应用程序中使用新的 PHP 功能,并迁移到 PHP 8.3,而无需将来进行任何代码更改,因为您的代码将在可用时自动使用内置函数。