我有一个JSON数组,包含如下内容:
$json =
Array (
[authmode] => ad
[usertype] => sam
[user] => BobJones
[server] => Array (
[0] => Array (
[ip] => 1.2.3.4
[title] => sony
[id] => Array (
[0] => 1.2.840.1.1.1
[1] => 1.2.840.1.1.2
)
)
[1] => Array (
[ip] => 10.20.30.40
[title] => panasonic
[id] => Array (
[0] => 1.2.840.1.1.10
[1] => 1.2.840.1.1.11
[2] => 1.2.840.1.1.12
[3] => 1.2.840.1.1.13
)
)
)
[recipient] => Array (
[0] => john@smith.org
[1] => jsmith@smith.com
)
[date] => 2014-12-31
[options] => Array (
[0] => alpha
[1] => beta
[2] => gamma
)
)
此阵列的某些元素是必需的,其他元素是可选的。我在一个单独的数组中保存所需的元素,包含它们的键及其值类型:
$req =
Array (
'authmode' => 'string',
'usertype' => 'string',
'user' => 'string'
'server' => 'array',
'ip' => 'string',
'title' => 'string'
'id' => 'array'
)
我创建了一个使用递归检查所需键的函数,并确保它们的值类型与$ req数组中的值匹配
function bob($key, $val, $arr){
echo '<br>Checking ' . $key . ' with value of ' . $val . ' within ' . $arr;
// is key found in base array?
if(array_key_exists($key, $arr)){
if(gettype($arr[$key]) == $val){
echo '... gettype reports that ' . $arr . '[' . $key . '] is a ' . $val . ' and is correct';
return true;
}
}
echo '<br>' . $key . ' not in base array, sending back to itself...';
// check arrays within this array
foreach ($key as $ele){
if(is_array($ele)){
echo '<br>' . $ele . ' is an array ....';
if(bob($key, $val, $ele)){
return true;
}
}
}
return false;
}
最后,我调用所有这些的方式如下:
foreach ($reqKeys as $key => $val){
if (!bob($key, $val, $json)){
echo '<p>Failed on ' . $key . ' being a ' . $val . '</p>';
}
}
该函数在基础数组上工作得很好,但是一旦我开始检查任何子数组(例如[server]数组),该函数就会在ip上返回错误而不是字符串,其中显然是
我得到的回应是:
Checking authmode with value of string within Array... gettype reports that Array[authmode] is a string and is correct
Checking usertype with value of string within Array... gettype reports that Array[usertype] is a string and is correct
Checking user with value of string within Array... gettype reports that Array[user] is a string and is correct
Checking server with value of array within Array... gettype reports that Array[server] is a array and is correct
Checking ip with value of string within Array
ip not in base array, sending back to itself...
Failed on ip being a string
对更好的做事方式有任何想法或意见吗?
答案 0 :(得分:1)
由于您希望进行更复杂的比较,而不仅仅是键入,您应该使用策略模式并在$req
中传递验证回调。
$req
将如下所示:
$req = [
'authmode' => 'is_string',
'usertype' => 'is_string',
'user' => 'is_string',
'server' => function ($servers) {
// check is `server` is an array
if (!is_array($servers)) {
return false;
}
foreach ($servers as $server) {
// check conditions for each server.id, server.ip and server.title
if (
!is_array($server['id']) ||
!is_string($server['ip']) ||
!is_string($server['title'])
) {
return false;
}
// validate all server.id's
foreach ($server['id'] as $id) {
if (!is_string($id)) {
return false;
}
}
}
return true;
}
];
由于$arr['server']
是一个数组,因此您必须使用自己的函数验证其内容,因为您无法轻松引用它们。
这使我们的验证功能非常简单:
function isPropertyValid($key, $isValid, $arr) {
if (!isset($arr[$key])) {
return false;
}
return isset($arr[$key]) && $isValid($arr[$key]);
}
你不再需要那里很好的递归,因为它会带来一些复杂性。
你也可以抛出一个验证所有需求的函数,而不是一个一个地执行:
function isArrayValid($requirements, $arr) {
foreach ($requirements as $key => $validator) {
if (!isPropertyValid($key, $validator, $arr)) {
return false;
}
}
return true;
}
我已经汇总了一个工作示例here。