phpforeach多维数组递归不起作用


php foreach multidimensional array recursion not working?

我最后一个问题的后续内容:对于循环,在多维数组中的数字键上移动更深

我有这个数组作为输入:

Array
(
  [0] => apl_struct Object
    (
      [funcname] => say
      [args] => Array
        (
          [0] => Array
            (
              [0] => apl_struct Object
                (
                  [funcname] => text
                  [args] => Array
                    (
                      [value] => hello
                    )
                )
            )
        )
    )
)

我现在有两个功能在为我工作。一个是仅用于获取关联数组中的下一个键/值的函数。next()、prev()等都不像索引数组那样对我有效:

function getnext($array, $key) {
  $keys = array_keys($array);
  if ((false !== ($p = array_search($key, $keys))) && ($p < count($keys) - 1)) {
    return array('key' => $keys[++$p], 'value' => $array[$keys[$p]]);
  } else {return false;}
}

下一个函数是我的执行器或构造器。他为我创建了一个半xml结构。我试图为跳过数字键添加递归。它们显然是无稽之谈,可以跳过。

然后我想检查非数字键的所有值是否都是数组。如果它是一个数组,它指示要遵循的参数和输出应该看起来像:INPUT。

如果不是,它要么是functionname(funcname),要么实际上是一个真正的值,比如"hello"。

function arr2xml($array, $level = 1, $pos = 1) {
  $xml = '';
  foreach ($array as $key => $value) {
    if (is_object($value)) {$value = get_object_vars($value);}// convert object to array
      if (is_numeric($key)) {
        $xml .= arr2xml($value);
      } else {
        if (!is_array($value)) {
          switch ($key) {
            case 'funcname':
              $nextkey = getnext($array, $key);
              $xml .= str_repeat("'t", $level) . "<apl:$value>'n";
              $xml .= arr2xml($nextkey['value'], $level++);
              $xml .= str_repeat("'t", $level) . "</apl:$value>'n";
              break;
            case 'value':
              $xml .= str_repeat("'t", $level) . "'t$value'n";
              break;
          }
        } else {
            $xml .= str_repeat("'t", $level) . "<$key pos='$pos'>'n't";
            $xml .= arr2xml($value, $level++, $pos++);
            $xml .= str_repeat("'t", $level) . "</$key>'n";
        }
      }
  }
return $xml;
}

但到目前为止,我从中得到的是:函数名称插入正确。它是说和文本。此外,在某些异常情况下,-tag和值会正确执行。

<apl:say>
<apl:text>
    hello
    </apl:text>
    <args pos='1'>
        hello
      </args>
    </apl:say>
    <args pos='1'>
    <apl:text>
    hello
    </apl:text>
    <args pos='1'>
        hello
      </args>
      </args>
</xml>

对我来说,递归似乎并没有真正起作用。我是不是遗漏了什么?我试着从前面提到的帖子中重建它。

此外,我想知道我在这里得到的多重输出。标签似乎填对了,但实际的安排让我很困惑。

我原以为输出是这样的:

<apl:say>
  <args pos='1'>
    <apl:text>
      <args pos='1'>
      hello
      </args>
    </apl:text>
  </args>
</apl:say>

提前感谢

TL;DR

它是(完全多余的函数)getnext()arr2xml()如何递归的组合。我在这里提供了一个arr2xml()替换功能,它可以随心所欲,而不需要getnext()

下面将详细描述代码中出现的错误,以及我建议如何修复它。

function arr2xml($array, $level = 0, $pos = 1) {
  $xml = '';
  foreach ($array as $key => $value) {
    if (is_object($value)) {
      $value = get_object_vars($value);
    }
    if (is_numeric($key)) {
      $xml .= arr2xml($value, $level+1);
      continue;
    } else {
      if (!is_array($value)) {
        switch ($key) {
          case 'funcname':
            array_shift($array);
            $xml .= str_repeat("    ", $level) . "<apl:$value>'n";
            $xml .= arr2xml($array, $level+1);
            $xml .= str_repeat("    ", $level) . "</apl:$value>'n";
            return $xml;
          case 'value':
            $xml .= str_repeat("    ", $level) . "    $value'n";
            return $xml;
        }
      } else {
          $xml .= str_repeat("    ", $level) . "<$key pos='$pos'>'n    ";
          $xml .= arr2xml($value, $level+1, $pos+1);
          $xml .= str_repeat("    ", $level) . "</$key>'n";
          return $xml;
      }
    }
  }
  return $xml;
}

这里有一个eval.in,显示了这个新函数在你提供的相同数据结构上的使用,或多或少地给了你想要的输出(空白可能不是你想要的,我把它留给你练习。)

你的代码出了什么问题

funcname'say'时,条件case 'funcname':调用getnext()$key设置为'funcname'$array设置为:

array(2) {
  ["funcname"]=>
  string(3) "say"
  ["args"]=>
  array(1) {
    [0]=>
    array(1) {
      [0]=>
      object(apl_struct)#1 (2) {
        ["funcname"]=>
        string(4) "text"
        ["args"]=>
        array(1) {
          ["value"]=>
          string(5) "hello"
        }
      }
    }
  }
}

然后在该数组($p = array_search($key, $keys))中找到'funcname',并创建一个仅包含数组中下一项的值的新数组:

return array('key' => $keys[++$p], 'value' => $array[$keys[$p]]);

结果是一个不再包含'args'密钥的数组:

array(2) {
  ["key"]=>
  string(4) "args"
  ["value"]=>
  array(1) {
    [0]=>
    array(1) {
      [0]=>
      object(apl_struct)#1 (2) {
        ["funcname"]=>
        string(4) "text"
        ["args"]=>
        array(1) {
          ["value"]=>
          string(5) "hello"
        }
      }
    }
  }
}

因此,你永远不会得到你想要的标签,因为getnext()已经破坏了数据结构,删除了你想要找到的密钥来构建它

重复的值可以通过早些时候从内部递归返回来解决。现在,您正在递归,处理"内部"节点,然后返回顶部并再次处理它们。

相反,我们可以完全删除getnext(因为它甚至不做你想要的事情),我们可以只使用array_shift来丢弃数组的最左边的值。然后,我们像往常一样继续处理$array

花了一段时间后,我为我的问题想出了这个解决方案:

function apl2xml($array, $tlevel = 0) {
    $ret = '';
    $ret .= str_repeat("'t", $tlevel) . "<apl>'n";
    foreach ($array as $key => $value) {
        $ret .= $this->aplstruct2xml($value, $tlevel + 1);
    }
    $ret .= str_repeat("'t", $tlevel) . "</apl>'n";
    return $ret;
}
function aplstruct2xml($apl_struct, $tlevel = 0) {
    $ret = '';
    if ($apl_struct->funcname == 'text') {
        $ret .= str_repeat("'t", $tlevel) . "<text>'n";
        $ret .= str_repeat("'t", $tlevel);
        $ret .= $apl_struct->args[0] . "'n";
        $ret .= str_repeat("'t", $tlevel) . "</text>'n";
    } else {
        $ret .= str_repeat("'t", $tlevel) . "<aplfunc:{$apl_struct->funcname}>'n";
        foreach ($apl_struct->args as $key => $value) {
            $ret .= str_repeat("'t", $tlevel + 1) . "<arg pos='$key'>'n";
            $ret .= $this->apl2xml($value, $tlevel + 2);
            $ret .= str_repeat("'t", $tlevel + 1) . "</arg>'n";
        }
        $ret .= str_repeat("'t", $tlevel) . "</aplfunc:{$apl_struct->funcname}>'n";
    }
    return $ret;
}

事实证明,我根本不需要任何递归。。

所谓的apl只是由一个apl_struct组成,它可以包含更多的apl/apl_struct's