【问题标题】:PHP - How to access a deep array's contents, building the path to it dynamicallyPHP - 如何访问深度数组的内容,动态构建它的路径
【发布时间】:2012-04-18 16:51:52
【问题描述】:

我正在尝试从使用闭包表存储的关系数据库内容在 PHP 中构建一个分层数组。对于给定的结果,我将拥有到 LEAF 节点的完整路径,下面看起来像我的结果集。

1~root~根节点

1~root~根节点>>>2~category1~第一类

1~root~根节点>>>3~category2~第二类

1~root~根节点>>>2~category1~第一类>>>4~subCatOfCategory1~Cat 1的SubCategory

无论如何,这些是我的数据库结果。所以我想遍历它们并在 PHP 中构建一个层次结构,这样我就可以将它转换为 JSON 并在 DOJO 中渲染一棵树

所以当我遍历每一行时,我正在为叶子构建一个“路径”,因为我只需要在元素是“叶子”时向树添加一个元素......沿着这个想法,我决定我会标记每个结果,使用“>>>”作为分隔符,给我该行中的节点。然后我遍历这些节点,用“~”标记每个节点,这给了我每个节点的属性。

所以,我有一个 for 循环来处理每个 ROW,它基本上确定如果正在处理的节点不是叶子,则将其 ID 添加到一个数组中,该数组用于跟踪到达最终叶子的路径处理。然后,当我最终到达 LEAF 时,我可以调用一个函数来插入一个节点,使用我一路编译的 PATH。

希望这一切都有意义.. 所以我已经包含了下面的代码.. 考虑上面的第二个结果。当我处理完整个结果并即将调用函数 insertNodeInTreeV2() 时,数组如下所示...

$fullTree 是一个包含 1 个元素的数组,索引为 [1] 该元素包含一个包含四个元素的数组:ID(1)NAME(root)Description(the root node)CHILDREN(empty array)

$pathEntries 是一个只有一个元素 (1) 的数组。也就是说,插入的LEAF节点的PATH是由节点[1],也就是根节点。

$nodeToInsert 是一个包含四个元素的数组:ID(2)NAME(category1)Description(First Category)CHILDREN(empty array)

$treeRootPattern 是一个字符串,其中包含我用来存储整个数组/树的变量名称,在本例中为“fullTree”。

private function insertNodeInTreeV2( array &$fullTree, array $pathEntries, array $nodeToInsert, $treeRootPattern )
{
  $compiledPath = null;
  foreach ( $pathEntries as $path ) {
    $compiledPath .= $treeRootPattern . '[' . $path . '][\'CHILDREN\']';
  }
  // as this point $compiledPath = "fullTree[1]['CHILDREN']"
  $treeVar = $$compiledPath;
}

所以当我进行赋值时,$treeVar = $$compiledPath;,我认为我将变量 $treeVar 设置为等于 $fullTree[1]['CHILDREN'](我在调试器中验证了一个有效的数组索引)。即使我将 $compiledPath 的内容粘贴到 Eclipse 调试器中的新表达式中,它也会向我显示一个空数组,这是有道理的,因为它位于 $fullTree[1]['CHILDREN']

但是,运行时却告诉我以下错误...

troller.php 第 85 行 - 未定义变量:fullTree[1]['CHILDREN']

对此的任何帮助将不胜感激......如果你有更好的方法让我从我描述的结果集中获得我正在尝试构建的分层数组,我会渴望采用更好的方法。

已更新以添加调用上述函数的代码 -- 如上所述,数据库结果的 FOR 循环过程行

foreach ( $ontologyEntries as $entry ) {

        // iterating over rows of  '1~~root~~The root node>>>2~~category1~~The first category
        $nodes = explode( '>>>', $entry['path'] );
        $numNodes = count( $nodes ) - 1 ;

        $pathToNewNode = null;  // this is the path, based on ID, to get to this *new* node
        for ( $level = 0; $level <= $numNodes; $level++ ) {

            // Parse the node out of the database search result
            $thisNode = array(
                'ID'          => strtok($nodes[$level], '~~'),  /*   1   */
                'NAME'        => strtok( '~~'),                 /*   Root   */
                'DESCRIPTION' => strtok( '~~'),                 /*   This is the root node   */
                'CHILDREN'    => array()
            );

            if ( $level < $numNodes ) {   // Not a leaf, add it to the pathToThisNodeArray
                $pathToNewNode[] = $thisNode['ID'];
            }
            else {
                // processing a leaf, add it to the array
                $this->insertNodeInTreeV2( $$treeRootPattern,  $pathToNewNode, $thisNode, $treeRootPattern );
            }

        }

    }

【问题讨论】:

  • 唷,一个巨大的问题!我有一种感觉,它可以被压缩成几个段落——让你的读者更容易理解——而是将代码(包括第 85 行)放在它的位置。
  • 不同的方法:在插入子树时使用对注释的引用而不是变量变量 ($$treeRootPattern)。如果您必须使用$foo["bar"] 之类的字符串访问变量,您将无法使用eval。见stackoverflow.com/questions/5065294/…
  • 解释错误信息:$fullTree[1]['CHILDREN'] 不是一个有效的变量名。只有$fullTree 是名称,其余的由PHP 稍后解释。 $fullTree[1]['CHILDREN'] 读作:访问数组 $fullTree。转到索引1 指向的内存。将其解释为数组。转到索引CHILDREN 指向的内存。所以从一开始就没有一个名为$fullTree[1]['CHILDREN']的变量,所以你不能通过变量变量访问它。 :-)
  • 谢谢巴斯蒂,现在这很有意义——我可以构建一个表示变量的字符串,但不能构建一个数组的索引。谢谢。
  • @halfer - 以后我会考虑您关于问题简洁性的建议。我的想法是“越多越好”,因此潜在的回答者可以阅读他们需要的内容,忽略其余部分,而不必要求澄清……但我想我可以用更少的词来包含所有内容。已注明。

标签: php arrays multidimensional-array hierarchy hierarchical-data


【解决方案1】:

请在您的问题下方查看我的 cmets 以获得解释。

$paths = array(
    "1~root~the root node",
    "1~root~the root node>>>2~category1~First category",
    "1~root~the root node>>>3~category2~Second category",
    "1~root~the root node>>>2~category1~First category>>>4~subCatOfCategory1~SubCategory of Cat 1"
);

$tree = array();

foreach ($paths as $path)
{
    $currentNode = &$tree;

    $parts = explode(">>>", $path);

    foreach ($parts as $part)
    {
         $node = explode("~", $part);

         // create all nodes along this path
         if (!isset($currentNode[$node[0]]))
         {
              $currentNode[$node[0]] = array(
                "ID"            => $node[0],
                "NAME"          => $node[1],
                "DESCRIPTION"   => $node[2],
                "CHILDREN"      => array(),
              );
         }

         $currentNode = &$currentNode[$node[0]]["CHILDREN"];
    }
}

var_dump($tree);

输出:

array
  1 => 
    array
      'ID' => string '1' (length=1)
      'NAME' => string 'root' (length=4)
      'DESCRIPTION' => string 'the root node' (length=13)
      'CHILDREN' => 
        array
          2 => 
            array
              'ID' => string '2' (length=1)
              'NAME' => string 'category1' (length=9)
              'DESCRIPTION' => string 'First category' (length=14)
              'CHILDREN' => 
                array
                  4 => 
                    array
                      'ID' => string '4' (length=1)
                      'NAME' => string 'subCatOfCategory1' (length=17)
                      'DESCRIPTION' => string 'SubCategory of Cat 1' (length=20)
                      'CHILDREN' => &
                        array
                          empty
          3 => 
            array
              'ID' => string '3' (length=1)
              'NAME' => string 'category2' (length=9)
              'DESCRIPTION' => string 'Second category' (length=15)
              'CHILDREN' => 
                array
                  empty

循环将创建路径中包含的所有节点,因此如果您还插入了1~root~the root node&gt;&gt;&gt;2~category1~First category,则无需插入1~root~the root node

如果节点是路径的最后一个节点,您可以通过仅创建节点来更改此设置。路径的长度是count($parts),您可以计算您在内部 foreach 循环中所处的级别。

我希望这是你想要的。

【讨论】:

  • Crumbs,我认为您应该阅读整个问题 +5!不错,+1。
  • 谢谢!解决这个问题很有趣。 :-)
  • 巴斯蒂,非常感谢。我讨厌把事情复杂化。这完全符合预期。我很感激你的回答。我无法投票赞成你的答案,因为我还没有足够的声望点。
猜你喜欢
  • 2018-05-07
  • 2013-10-02
  • 2020-04-25
  • 2012-12-24
  • 1970-01-01
  • 2022-10-08
  • 1970-01-01
  • 1970-01-01
  • 2021-08-17
相关资源
最近更新 更多