PHP中最优雅的树木行走方式

PHP中最优雅的树木行走方式,php,tree,Php,Tree,我有这样的树: $tree = array("A", array( array("B", 1), array("C", 2), array("D", array("E", array("F")), array("G")), array("H", 3))); 每个节点都是一个数组,节点的类型是它的第

我有这样的树:

$tree = array("A", array(
            array("B", 1),
            array("C", 2),
            array("D",
                array("E",
                    array("F")),
                array("G")),
            array("H", 3)));
每个节点都是一个数组,节点的类型是它的第一个元素,其他元素是节点的参数(它们可以是其他节点的列表、单个节点、某些值等;节点可以没有参数、一个参数或多个参数)

你认为走这类树最优雅的方式是什么

我提出了两种可能性:

1) 使用
开关
语句

/*
 * + shorter
 * + fall-througs (easy way to handle more nodes with same code)
 *
 * - worse readability
 */
function my_tree_walker($tree)
{
    switch ($tree[0]) {
        case 'A':
            list($_, $subnodes) = $tree;
            $ret = '';

            foreach ($subnodes as $subnode) {
                $ret .= my_tree_walker($subnode);
            }

            return $ret;

        break;
        case 'B': /*...*/ break;
        case 'C': /*...*/ break;
        case 'D': /*...*/ break;
        case 'E': /*...*/ break;
        case 'F': /*...*/ break;
        case 'G': /*...*/ break;
        case 'H': /*...*/ break;
    }
}
2) 对象,并为每个节点类型指定方法

/*
 * + better readability
 * + more declarative
 *
 * - longer
 * - `new static` is PHP >=5.3 only
 */

abstract class TreeWalker
{
    protected function __construct(){}

    final protected function walk($node)
    {
        $nodetype = array_shift($node);
        return call_user_func_array(array($this, 'walk' . $nodetype), $node);
    }

    public static function w($tree)
    {
        $instance = new static;
        return $instance->walk($tree);
    }
}

final class MyTreeWalker extends TreeWalker
{
    protected function __construct()
    {
        // initialize
    }

    private function walkA($subnodes)
    {
        $ret = '';

        foreach ($subnodes as $subnode) {
            $ret .= $this->walk($subnode);
        }

        return $ret;
    }

    private function walkB($n) { /*...*/ }
    private function walkC($n) { /*...*/ }
    private function walkD($subnode) { /*...*/ }
    private function walkE() { /*...*/ }
    private function walkF() { /*...*/ }
    private function walkG() { /*...*/ }
    private function walkH($n) { /*...*/ }
}
或者你建议更优雅的方式行走树木

我还认为节点是对象,而不是单独的树漫游器,每个节点都有内部漫游的方法。然而,我认为这将使代码更难维护,因为walkers的部分代码将被放置在不同的位置,并且对于更多的节点使用相同的代码将更加困难。

请看:


    • 我认为简单就是优雅

      不需要重新发明轮子!PHP附带了一些功能,可以为您完成所有工作


      有几个要检查的是和

      我结合了这两种方式并创建了DSL:

      A ($subnodes) {
          $ret = '';
          foreach ($subnodes as $subnode) {
              $ret .= WALK($subnode);
          }
      
          return $ret;
      }
      B ($n) { /*...*/ }
      C ($n) { /*...*/ }
      D ($subnode) { /*...*/ }
      E () { /*...*/ }
      F () { /*...*/ }
      G () { /*...*/ }
      H ($n) { /*...*/ }
      

      这已转换为PHP。

      我建议使用以下库:

      TreeWalker是一个简单的小型库,它可以帮助您更快地在PHP中操作结构

      • getdiff()-获取json差异
      • walker()-编辑json(递归)
      • structMerge()-连接两个结构
      • createDynamicallyObjects()-通过动态键创建嵌套结构
      • getDynamicallyValue()-动态获取结构属性
      • setDynamicallyValue()-动态访问结构属性以设置值

      我制作了一个简单的递归函数,可以有效地遍历树。给你

         function deep_cetegories($categories){
           foreach($categories as $category)
        {
          print_r((json_encode($category['category_name'])));
          if(isset($category['children']))
          {
              deep_cetegories($category['children']);
          }
      
        }
      }
      

      问题是,并非所有节点都会得到相同的处理。仍然需要开关之类的东西。还是我遗漏了什么?@Jak遍历本身与数据结构无关,只要它们是可写的。如果您想以不同的方式对待元素,是的,您仍然需要一个switch语句,或者您可以使用对象而不是数组,并利用动态分派。正如我在问题中所写的,我考虑了对象,我认为它们弊大于利。问题是所有节点的处理方式都不相同。仍然需要开关之类的东西。或者我遗漏了什么?你能提供一个你希望对节点做什么的例子,让我们更好地了解你想要完成什么吗?我正在尝试在我的PEG生成器中重构树漫游器(比如:,以及以下以“g”开头的方法)。我想将它们分开(单独的类/函数),并使用相同的语言结构。