【问题标题】:Fastest way to check if a string is JSON in PHP?在 PHP 中检查字符串是否为 JSON 的最快方法?
【发布时间】:2011-08-27 20:34:47
【问题描述】:

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

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

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

【问题讨论】:

  • 考虑只使用一次json_decode...另外,检查json_decode的输入和返回值。
  • 那么,答案是哪一个?
  • 这里的三元开关是多余的。您的语句已经评估为布尔值。
  • 接受刘易斯多诺万的回答......它工作正常

标签: php json error-handling json-deserialization jsonresult


【解决方案1】:

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

function is_JSON($string) {

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

【讨论】:

  • 我也不太习惯,呵呵。由于我使用的 PhpStorm 和 Magento Code Sniffer 工具总是抱怨我,我开始采用这种方法。最后,我们得到了更清晰的代码并习惯了它。 :P
  • Is null valid JSON?的相关问题。
  • 感谢您的提醒,@ikhvjs。如果你想预测这种情况,你可以在上面的函数内容前面加上条件:if (is_null($string)) return TRUE;
【解决方案2】:

最快的方法是“可能解码”可能的 JSON 字符串

这真的是最快的方法吗?

如果您想解码复杂对象或更大的数组,这是最快的解决方案! 除了速度快之外,这是唯一可以可靠处理任何类型的输入值的解决方案 - 其他函数在某些情况下会抛出错误或返回不正确的结果。

如果您的 JSON 字符串包含短值(例如,字符串、数字或仅具有 1-2 个属性的对象),则此 SO 问题中的所有解决方案都具有类似的性能

这是一个带有比较的快速概览 - 您可以在链接的要点中找到测试用例。最后一列使用此答案中的代码:

PHP version: 7.4.21

test1: json_last_error() == JSON_ERROR_NONE
test2: is_object( json_decode() )
test3: json_decode() && $res != $string
test4: preg_match()
test5: "maybe decode" approach

      | test1    | test2    | test3    | test4    | test5    
   #0 | 0.0147   | 0.0109 ✓︎ | 0.0119   | 0.0177   | 0.0194   
   #1 | 0.0129   | 0.0106   | 0.0098   | - INV -  | 0.0078 ✓︎ 
   #2 | 0.0076   | 0.0075   | 0.0063 ✓︎ | 0.0083   | 0.0133   
   #3 | 0.0126   | 0.0105   | 0.0096 ✓︎ | - INV -  | 0.0172   
   #4 | 0.0070   | - INV -  | 0.0061 ✓︎ | 0.0141   | 0.0134   
   #5 | 0.0114   | - INV -  | 0.0101   | 0.0075 ✓︎ | 0.0168   
   #6 | 0.0203   | - INV -  | 0.0195   | 0.0073 ✓︎ | 0.0259   
   #7 | 0.0046   | - INV -  | - INV -  | 0.0077   | 0.0031 ✓︎ 
   #8 | 0.0066   | - INV -  | - INV -  | 0.0081   | 0.0020 ✓︎ 
   #9 | 1.0781   | - INV -  | 1.0555   | 0.0998 ✓︎ | 1.0385   
  #10 | 0.3183 ✓︎ | 0.3246   | 0.3270   | 1.0186   | 0.3311   
  #11 | 0.0071   | 0.0068   | 0.0067 ✓︎ | - INV -  | 0.0079   
  #12 | - ERR -  | - ERR -  | - ERR -  | - ERR -  | 0.0025 ✓︎ 
  #13 | - ERR -  | - ERR -  | - ERR -  | - ERR -  | 0.0024 ✓︎ 
  Avg | 0.1251   | 0.0618 ✓︎ | 0.1463   | 0.1321   | 0.1072

请注意,最快的解决方案会产生最不正确的结果。在所有其他解决方案中,“可能解码”方法不仅是最快的,而且是唯一具有正确结果的解决方案。

这里是完整的性能比较脚本,你可以看到我用于比较的测试数据:https://gist.github.com/stracker-phil/6a80e6faedea8dab090b4bf6668ee461


“可能解码”逻辑/代码

在尝试解码 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 false; }

    // 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 问题中的任何其他解决方案时,您将得到 dramatically degraded performance + 错误的返回值(甚至是致命错误)。此代码防弹且高性能。

【讨论】:

  • 我不确定,为什么这个答案被否决甚至有删除请求。我的性能测试清楚地表明这是迄今为止最快的方法。这是性能比较脚本:gist.github.com/stracker-phil/6a80e6faedea8dab090b4bf6668ee461
  • +1 纯粹的努力 :) 我认为当它实际上有 8 个“if”语句时,你的测试实际上更快,这真是令人惊讶。我认为人们不会喜欢它,因为它一点也不优雅,而且除非您需要检查大约一百万位文本,否则它实际上并没有太大的开销差异。
  • @EnigmaPlus 谢谢 :) 没错,代码不是优雅的单行代码,但问题是要找到 最快 方式,而不是最优雅/最短的方式。 json_decode 更短,但需要 PHP 初始化一个内部 JSON-Parser 实例,该实例非常复杂并且比 8 个简单的 ifs 慢得多 ?
  • 你的例子 $json_data = json_decode($value,null,1);在评估类似 '{"a":5}' 或 '[1,2,3]' 时返回 NULL。应该是两个级别,比如:json_decode($value,null,2);
  • is_numeric($value) 应该是第一个评估。
【解决方案3】:

问题的答案

函数json_last_error返回JSON编码和解码过程中发生的最后一个错误。所以检查有效 JSON 的最快方法是

// 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
}

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

检查确切错误的完整程序

在开发期间知道确切的错误总是好的。这是基于 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 输入进行测试

$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

由于 PHP 5.2 不支持json_last_error,您可以检查编码或解码是否返回布尔值FALSE。这是一个例子

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

【讨论】:

  • 小精度:如果这个 json 是有效的,但之前解码的一个是无效的,你的代码会正常工作,因为:“返回最后一个错误(如果有的话)发生在 最后 JSON编码/解码。"
  • 感谢@Madan,“json_decode”验证解决了我运行 PHP 7.0 的问题。
  • 当然 json_decode 可能只返回 false 为文字 false,所以还应该检查 ((strlen($json) === 5) &amp;&amp; ($json !== 'false')) 以避免该边缘?
  • @Bruno 如果最后一次解码没有错误,则json_last_error 返回JSON_ERROR_NONE
【解决方案4】:
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;
}

【讨论】:

  • 恕我直言,如果您还想实际使用解码的对象,最好的解决方案应该是 json
  • 你是对的。我更新了答案
【解决方案5】:
function isJson($string) {
   json_decode($string);
   return json_last_error() === JSON_ERROR_NONE;
}

【讨论】:

  • 看起来每个人都喜欢这个答案。任何解释为什么?
  • 检查{[ 或任何其他文字的第一个符号的字符串的第一个字符可能会大大加快这一速度,因为预计许多传入的字符串都是非 JSON 的。跨度>
  • $phone = '021234567'; var_dump(isJson($phone));返回真不!它应该返回 false。
  • 请注意,无论您将其指定为字符串还是真数,此函数也会对任何数字返回 true。 6.5 = true, '300' = true, 9 = true 等。所以这可能是一个有效的 JSON 值,但如果您只想使用 {}[] 检查有效的 JSON 字符串,该函数可能不会像您预期的那样运行;
  • 值得注意的是,这在理论上是正确的。不幸的是,PHP 的json_decode 函数有许多错误,这将允许以奇怪的方式解析无效的 JSON。 isJson('0123') 应该返回 false,因为 0123 不是 JSON,但是 isJson('123') 应该返回 true,因为 123 JSON。似乎有些人不知道JSON allows values to be more than just an object or array。有效的 JSON 值可以是对象、数组、数字、字符串、布尔值和 null
【解决方案6】:

如果本地文件stations.json 无效、丢失或超过一个月,请采取措施。

if (!is_array(json_decode(@file_get_contents("stations.json"))) || time() > filemtime("stations.json") + (60*60*24*31)){
  // The json file is invalid, missing, or is more than 1 month old
  // Get a fresh version
} else {
  // Up to date
}

【讨论】:

    【解决方案7】:
    $r = (array)json_decode($arr);
    if(!is_array($r) || count($r) < 1) return false;
    

    【讨论】:

    • 这个问题已经有 30 个其他答案,其中一个获得了 600 多票。这并不意味着一个新的答案不能为对话提供新的东西。但这确实意味着您的答案将真正受益于额外的解释。它与其他答案的区别是什么?为什么或何时有人更喜欢你的方法?语言是否发生了变化,使您的方法可行或使以前的方法无效?请编辑您的答案,以帮助将您的方法与过去十年贡献的其他 30 个答案区分开来。
    • 在当前版本的PHP中is_array总是会返回一个false,所以应该声明为一个数组然后检查它是否有值。而且它是一种更短的方式
    【解决方案8】:

    将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)

    【讨论】:

    • 非常好 :) 我很佩服你
    【解决方案9】:

    这是我推荐的

    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);
    }
    

    【讨论】:

      【解决方案10】:

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

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

      这个请求甚至不需要单独的函数。只需将 is_object 包裹在 json_decode 周围并继续。似乎这个解决方案让人们考虑太多了。

      【讨论】:

      • @RomanM.Kos 需要明确的是,如果数组是简单数组,那么除了is_object之外,还需要使用is_array,否则is_object对于简单数组会返回false编码为 JSON。所以@ggutenberg 在这种情况下是正确的。将 true 参数传递给 json_decode 会强制将对象作为数组返回。从理论上讲,您总是可以强制解码到一个数组并检查is_array,这应该可以工作。
      • @userabuser 如果我 json_encode($array) 用于简单的 PHP 数组,然后执行 json_decode($str) 我将收到对象,但不是数组。 json_decode($str, true) 强制转换为数组。为什么在你的代码中使用复杂的字符串?检查is_array(json_decode($str, true)),稍后当您阅读它时,您会明白解码必须只是一个数组。很难猜到is_object(json_decode($MyJSONArray))“哦,我在这里检查解码是否是一个数组?”
      • @RomanM.Kos 不,这不正确,codepad.viper-7.com/OFrtsq - 正如我所说,您始终可以强制 json_decode 返回一个数组以节省您检查对象和数组的时间,但如果您不这样做't AND 你json_decode 什么是一个简单的数组开始,你将收到一个数组作为解码的回报,而不是一个对象。如果您想始终强制对对象进行编码 IF 传递一个简单数组,则必须使用 JSON_FORCE_OBJECT
      • 投反对票:This request does not require a separate function even。严格来说,没有解决方案需要单独的函数。函数的重点是不是 让多行代码看起来像一行代码。该功能的重点是使 JSON 检查过程在您的应用程序中随处可见,以便不同的程序员(或随着时间的推移同一个程序员)不会在程序流程的不同阶段使用不同的检查程序。跨度>
      【解决方案11】:
      //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;
      }
      

      【讨论】:

        【解决方案12】:

        这是我创建的一个高性能且简单的函数(在使用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】:

          我的另一个建议:)

          function isJson(string $string) {
            return ($result = json_decode($string, true)) ? $result : $string;
          }
          

          【讨论】:

            【解决方案14】:

            这样就可以了:

            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

            要查看实际情况,请查看以下两个示例:

            【讨论】:

            • "hello" 是一个有效的 JSON,它既不是对象也不是数组,json_last_error() 就足够了
            • json_last_error() 当您 json_decode() 字符串 "hello" 时返回错误代码 4。此处示例:3v4l.org/lSsEo
            • 您的代码有误,hello 不是有效的 JSON,但 "hello"3v4l.org/OEJrQ
            【解决方案15】:

            嗨,这是我的库中的一个小 sn-p,在第一个条件下,我只是检查数据是否为 ​​json,如果正确解码则返回它,请注意 substr 用于性能(我还没有看到任何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
                }
            }
            

            【讨论】:

            • 已经发布了 34 个关于这个问题的答案,其中许多还赞同 JSON 必须表示数组或对象的(错误的)信念。这个答案与其他 3 打答案有什么不同吗?
            • 我相信这个答案有很多好处,对于大多数用例,我们已经知道我们期待一个 json 字符串,所以这是检查大括号,所以如果找不到,就不会不需要json_decode。来自我的 +1。
            【解决方案16】:

            我使用的最简单最快的方法是跟随;

            $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_decode()如果输入的字符串不是json或者无效json返回NULL。


            验证 JSON 的简单函数

            如果您必须在多个地方验证您的 JSON,您始终可以使用以下函数。

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

            在上面的函数中,如果它是一个有效的 JSON,你会得到 true。

            【讨论】:

            【解决方案17】:

            应该是这样的:

             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);
                }
            }
            

            【讨论】:

            • 我喜欢你检查它是否是一个字符串。如果字符串是数组或对象,则与第一个解决方案结合使用可以很好地避免ErrorException
            【解决方案18】:

            我已经尝试了其中的一些解决方案,但没有什么对我有用。我试试这个简单的东西:

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

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

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

            【讨论】:

            • 您的 JSON 可能只是一个数组,在这种情况下,它将是一个数组而不是 stdClass $foo = "[1, 1, 2, 3]"; var_dump(json_decode($foo)); => 数组(4) { [0]=> int(1) [1]=> int(1) [2]=> int(2) [3]=> int(3) }
            【解决方案19】:

            对 henrik 的回答进行简单修改,以触及最需要的可能性。

            (包括“{} 和 []”)

            function isValidJson($string) {
                json_decode($string);
                if(json_last_error() == JSON_ERROR_NONE) {
            
                    if( $string[0] == "{" || $string[0] == "[" ) { 
                        $first = $string [0];
            
                        if( substr($string, -1) == "}" || substr($string, -1) == "]" ) {
                            $last = substr($string, -1);
            
                            if($first == "{" && $last == "}"){
                                return true;
                            }
            
                            if($first == "[" && $last == "]"){
                                return true;
                            }
            
                            return false;
            
                        }
                        return false;
                    }
            
                    return false;
                }
            
                return false;
            
            }
            

            【讨论】:

              【解决方案20】:

              如果您的字符串表示 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)
              

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

              【讨论】:

              • 您可以将它放在 PHPUnit 测试用例中,而不是 var_dump。否则我既惊讶又高兴得知这是真的。
              • 当这个方法很好用时,为什么其他人都会有如此冗长的答案?谢谢。
              • 简单,可爱!没有检查“最快的方式”或性能方面的问题,但这确实涵盖了我曾经检查过的所有情况。这是臭名昭著的谚语“不要用大锤敲碎坚果”的经典例子。从程序员的角度来看,保持代码简单、简短和易于理解总是更好,性能与简单性是另一个超出本线程范围的争论。
              • 这是一个简洁的逻辑,但还要注意它对于空数组返回 false。例如:var_dump(isJson('[]')); // bool(false)。根据有关布尔值的文档,这是因为 PHP 将零元素的数组评估为假。这里是一个小的修改来调整return语句;它对处理这种情况的解码输出执行相同的比较:return $json !== false &amp;&amp; $str != $json;
              • @j13k 相同比较将 isJson('hello') 评估为 true,这不是有效的 json。这里特意选择了松散比较。我没有针对空数组/对象情况的快速解决方案,除了丑陋的return $json == '[]' || ...
              【解决方案21】:

              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;
              }
              

              【讨论】:

                【解决方案22】:

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

                $result = @json_decode($json,true);
                    if (is_array($result)) {
                        echo 'JSON is valid';
                    }else{
                        echo 'JSON is not valid';
                    }
                

                【讨论】:

                  【解决方案23】:

                  我们需要检查传递的字符串是否不是数字,因为在这种情况下 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;
                  }
                  

                  【讨论】:

                    【解决方案24】:
                    function is_json($input) {
                    
                        $input = trim($input);
                    
                        if (substr($input,0,1)!='{' OR substr($input,-1,1)!='}')
                            return false;
                    
                        return is_array(@json_decode($input, true));
                    }
                    

                    【讨论】:

                    • @ 用于调试(隐藏错误),但绝对不推荐
                    【解决方案25】:

                    this answer 上扩展如下:

                    <?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);
                    ?>
                    

                    【讨论】:

                    • 如果在该检查中发现错误,是否应该在执行解码之前进行子字符串检查以节省时间?我想 4 个子字符串检查会比 json_decode 快,但如果有人能支持我这个假设,我会很感激对此的任何想法。
                    • 这是一个票价论据。我不知道所涉及的处理时间,但如果它更快,那么是的。
                    【解决方案26】:

                    全新功能,兼容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)
                    

                    【讨论】:

                      【解决方案27】:

                      使用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));
                      

                      然而,没有足够的性能爱好者来打扰这里的基准测试。

                      【讨论】:

                      • 完成递归正则表达式以在此处验证 JSON:stackoverflow.com/questions/2583472/regex-to-validate-json/… - 但事实证明 PHP json_decode 总是比 PCRE 正则表达式快。 (虽然它不是很优化,没有找到综合测试,并且在 Perl 中可能表现不同..)
                      • @vee 是的,感谢您的注意。但是让我们把它[错误地]留在这里,所以没有人真正在生产中使用它。
                      • @cartbeforehorse 好的,谢谢。然后,我修复了 PHP 双引号字符串上下文的转义问题。
                      • @cartbeforehorse 它没有。主要是装饰。这只是确实需要双重转义的文字反斜杠。对于\r\n\t,它只有意义,因此 PHP 不会对它们进行插值,而是让 PCRE 解释它们(仅/x 模式需要)。其他的事件并不严格需要它;但在所有字符串 PHP 上下文中仍然“反斜杠自行转义”。所以人们可以认为它更准确。
                      • @mario 好的,我明白了。所以基本上,PHP 在 reg-exp 引擎看到它之前转义了反斜杠。就 reg-exp 引擎而言,字符串中的反斜杠数量只有我们人类所见的一半。 “就像 reg-exp 还不够复杂”
                      【解决方案28】:

                      之前我只是检查一个空值,这实际上是错误的。

                          $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";
                      

                      【讨论】:

                      • 不错的解决方案。很好地处理打字问题!
                      【解决方案29】:

                      另一种简单的方法

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

                      【讨论】:

                      • 这是不正确的。任何 PHP 类型都可以编码为 JSON,例如对象、字符串等,并且 json_decode 函数应该返回它们。仅当您始终解码数组且没有其他变量类型时,这才是正确的。
                      • @Chaoix 使用 json_decode($str,true) 使其将对象转换为数组,因此它将通过 is_array 检查。不过,您更正了字符串、整数等问题。
                      • 我明白你对 json_encode 的第二个参数的意思了。我仍然认为@Ahad Ali 的解决方案在打字方面要好得多,并且只在您的算法中执行一次 json_decode。
                      【解决方案30】:

                      您必须验证您的输入以确保您传递的字符串不为空,并且实际上是一个字符串。空字符串不是有效的 JSON。

                      function is_json($string) {
                        return !empty($string) && is_string($string) && is_array(json_decode($string, true)) && json_last_error() == 0;
                      }
                      

                      我认为在 PHP 中确定 JSON 对象是否甚至 具有 数据更为重要,因为要使用这些数据,您需要调用 json_encode()json_decode()。我建议拒绝空 JSON 对象,这样您就不会不必要地对空数据运行编码和解码。

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

                      【讨论】:

                      • +1 用于在现实环境中实际思考问题。
                      • 但是'0' 不是有效的 json...我为什么要小心呢? @Kzqai
                      • if(is_string($string) &amp;&amp; is_array(json_decode($string, true)) &amp;&amp; (json_last_error() == JSON_ERROR_NONE)){ // json is valid }else{ // not valid }
                      猜你喜欢
                      • 2021-10-11
                      • 1970-01-01
                      • 2011-05-30
                      • 2018-05-04
                      • 1970-01-01
                      • 1970-01-01
                      • 2013-05-26
                      • 1970-01-01
                      相关资源
                      最近更新 更多