我需要一个非常非常快的方法来检查字符串是否为JSON。我觉得这不是最好的方式:
function isJson($string) {
return ((is_string($string) &&
(is_object(json_decode($string)) ||
is_array(json_decode($string))))) ? true : false;
}
有没有表演爱好者想改进这种方法?
我需要一个非常非常快的方法来检查字符串是否为JSON。我觉得这不是最好的方式:
function isJson($string) {
return ((is_string($string) &&
(is_object(json_decode($string)) ||
is_array(json_decode($string))))) ? true : false;
}
有没有表演爱好者想改进这种方法?
当前回答
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;
}
其他回答
另一种简单的方法
function is_json($str)
{
return is_array(json_decode($str,true));
}
你真正需要做的就是…
if (is_object(json_decode($MyJSONArray)))
{
... do something ...
}
这个请求甚至不需要一个单独的函数。只需将is_object包装在json_decode周围,然后继续。似乎这个解决方案让人们花了太多心思。
为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)
使用json_decode“探测”它实际上可能不是最快的方法。如果它是一个嵌套很深的结构,那么实例化大量数组对象来丢弃它们是浪费内存和时间。
所以使用preg_match和RFC4627正则表达式来确保有效性可能会更快:
// 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字符串
这真的是最快的方法吗?
如果你想解码复杂的对象或更大的数组,这是最快的解决方案! 除了速度快之外,这是唯一可以可靠地处理任何类型输入值的解决方案——在某些情况下,其他函数会抛出错误或返回不正确的结果。
如果您的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 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问题中,当将一个非字符串传递给任何其他解决方案时,您将得到显著的性能下降+错误的返回值(甚至是致命的错误)。此代码是防弹和高性能的。