如何在PHP中使用连接字符串构建树?

时间:2012-11-08 11:50:36

标签: php mysql recursion

我尝试使用存储在mysql数据库中的连接字符串中的层次结构在PHP中创建树列表

这是我的表:

Screenshot of table

我希望重现这样的事情:

<ul>
  <li>
    <ul>
      <li></li>
      <li>
          <ul>
              <li></li>
              <li></li>
           </ul>
      </li>
      <li></li>
    </ul>
  </li>
  <li></li>
  <li></li>
</ul>

我知道我必须使用我无法达到的递归函数...

也许有人可以帮助我

2 个答案:

答案 0 :(得分:3)

没有评论的代码

请参阅下面的用法和数据集部分,了解您需要传递的内容以及如何使用这些功能:

function items_to_tree( $items ){
  $array = array();
  foreach( $items as $item ) {
    $parts = explode('.', $item['hierarchy']);
    $last = array_pop( $parts );
    $cursor = &$array;
    foreach ( $parts as $part ) {
      if ( !is_array($cursor[$part]) ) {
        $cursor[$part] = array();
      }
      $cursor = &$cursor[$part];
    }
    $cursor[$last]['#item'] = $item;
  }
  return $array;
}

function tree_to_ul( $tree ){
  $html = $children = '';
  foreach( $tree as $key => $item ){
    if ( substr($key,0,1) == '#' ) continue;
    $children .= tree_to_ul( $item );
  }
  if ( isset($tree['#item']) ) {
    $html .= '<li>' . PHP_EOL;
    $html .= '<em>' . $tree['#item']['menu_text'] . '</em>' . PHP_EOL;
    $html .= ( $children ? '<ul>' . $children . '</ul>' . PHP_EOL : '' );
    $html .= '</li>' . PHP_EOL;
    return $html;
  }
  else {
    return $children;
  }
}


带有注释和解释的

代码

将项目转换为树状结构的代码:

function items_to_tree( $items ){
  $array = array();
  foreach( $items as $item ) {
    /// split each hierarchy string into it's dot separated parts
    $parts = explode('.', $item['hierarchy']);
    /// pop off the last item of the array, we'll use this for assignment later
    $last = array_pop( $parts );
    /// create a reference to our position in the array we wish to fill out
    $cursor = &$array;
    /// step each hierarchy part and travel down the array structure, 
    /// just like you would if you typed an array path manually. 
    /// i.e. $array[$part][$part][...] and so on
    foreach ( $parts as $part ) {
      /// if at this point in the array, we don't have an array, make one.
      if ( !is_array($cursor[$part]) ) {
        $cursor[$part] = array();
      }
      /// ready for the next step, shift our reference to point to the next
      /// $part in the array chain. e.g. if $cursor pointed to `$array[$part]`
      /// before, after the next line of code the $cursor will point 
      /// to `$array[$oldpart][$part]`
      $cursor = &$cursor[$part];
    }
    /// we popped the last item off the $parts array so we could easily
    /// assign our final value to where the $cursor ends up pointing to.
    /// starting with a hierarchy of '00001.00002.00003' would mean at this
    /// point $cursor points to $array['00001']['00002'] and $last = '00003';
    /// so finally we get $array['00001']['00002']['00003']['#item'] = $item;
    $cursor[$last]['#item'] = $item;
    /// use '#item' to keep our item's information separate from it's children.
  }
  /// return our built up array.
  return $array;
}

将树结构转换为UL的代码:

function tree_to_ul( $tree ){
  /// start with nothing
  $html = $children = '';
  /// step each item found in the current level of $tree
  foreach( $tree as $key => $item ){
    /// if the item's key starts with a # skip, these contain
    /// our item's information and should not be treated as children
    if ( substr($key,0,1) == '#' ) continue;
    /// recurse this function so that we do the same for any child @ any level.
    $children .= tree_to_ul( $item );
  }
  /// if at this level a #item has been set, use this item information to
  /// add a title to our level. You could change this to add whatever info
  /// from your original database item that you'd like.
  if ( isset($tree['#item']) ) {
    $html .= '<li>' . PHP_EOL;
    $html .= '<em>' . $tree['#item']['menu_text'] . '</em>' . PHP_EOL;
    $html .= ( $children ? '<ul>' . $children . '</ul>' . PHP_EOL : '' );
    $html .= '</li>' . PHP_EOL;
    return $html;
  }
  /// if there wasn't an item, just return the traversed children.
  else {
    return $children;
  }
}

数据集:

/// I simplified your dataset to an array, this could easily be generated
/// from a database query. You could also convert my code so that you
/// don't have to pre-generate an array, and instead could process after
/// each fetch from the database.

$items = array(
  array('hierarchy' => '00001',             'menu_text' => 'One'),
  array('hierarchy' => '00002',             'menu_text' => 'Two'),
  array('hierarchy' => '00002.00001',       'menu_text' => 'Three'),
  array('hierarchy' => '00002.00002',       'menu_text' => 'Four'),
  array('hierarchy' => '00002.00003',       'menu_text' => 'Five'),
  array('hierarchy' => '00002.00004',       'menu_text' => 'Six'),
  array('hierarchy' => '00003',             'menu_text' => 'Seven'),
  array('hierarchy' => '00003.00001',       'menu_text' => 'Eight'),
  array('hierarchy' => '00003.00001.00001', 'menu_text' => 'Nine'),
  array('hierarchy' => '00003.00001.00002', 'menu_text' => 'Ten'),
  array('hierarchy' => '00003.00001.00003', 'menu_text' => 'Eleven'),
  array('hierarchy' => '00003.00002',       'menu_text' => 'Twelve'),
);

用法:

/// Simple usage :) if a little complex explanation

$tree = items_to_tree( $items );
$html = tree_to_ul( $tree );

echo $html;


符合codegolf的利益;)

以下内容可以取代我的items_to_tree功能 - 但不建议这样做。

$a = array();
foreach($items as $i){
 eval('$a["'.str_replace('.','"]["',$i['hierarchy']).'"]=array("#item"=>$i);');
}

答案 1 :(得分:1)

    $refs = new stdClass();
    //Assuming $data is the result array of your query to fetch the data.
    foreach($data as $result)
    {
        $name = $result['hierarchy'];
        $parent = substr($result['hierarchy'],0,strrpos($result['hierarchy'],'.'));
        $thisref = &$refs->{$name};
        foreach($result as $k => $v)
        {
            $thisref->{$k} = $v;
        }
        if ($parent == '') {
            $tree->{$name} = &$thisref;
        } else {
            $refs->{$parent}->children->{$name} = &$thisref;
        }
    }

这将为您提供一个很好的对象,其中包含属性子节点中每个节点的子节点。

function drawUL($level){
    echo '<ul>';
    foreach($level as $li){
        echo '<li>'.$li->label;
        if(isset($li->children))drawUl($li->children);
        echo '</li>';
    }
    echo '</ul>';
}
drawUl($tree);