2010-06-22 64 views
1
最优雅的方式

我有这样一个树:走树木PHP

$tree = array("A", array(
      array("B", 1), 
      array("C", 2), 
      array("D", 
       array("E", 
        array("F")), 
       array("G")), 
      array("H", 3))); 

每个节点是一个数组,节点的类型是它的第一个元素和其他元素节点的参数(也可以是列表其他节点,单个节点,一些值等;节点可以没有参数,一个参数或多个参数)。

您认为最优雅的方式来走这些类型的树木?

我想出了两种可能性:

1)使用switch声明

/* 
* + 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) { /*...*/ } 
} 

还是你建议更优雅行走树的方式?

我也认为节点是对象,而不是独立的树步行者,每个节点都有内部散步的方法。不过,我认为这会让代码难以维护,因为步行者代码的一部分将被放置在不同的位置,并且使用相同的代码更难以用于更多的节点。

回答

0

我结合两种方式,创造了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。

3
+0

的问题是所有节点都不会被处理一样。仍然需要开关或其他东西。或者我错过了什么? – 2010-06-22 20:56:37

+0

@Jak遍历本身独立于数据结构,只要它们是可迭代的。如果你想对待不同的元素,是的,你仍然需要一个switch语句,或者你可以使用对象而不是数组,并利用动态分派。 – Artefacto 2010-06-22 22:16:54

+0

正如我在我的问题中写的那样,我考虑过对象,我认为它们会比弊端更坏。 – 2010-06-23 13:48:19

2

我想简单优雅。

不需要重新发明轮子! PHP配备了SPL (Standard PHP Library),它提供了几个Iterators,可以为你做所有的工作。

少数退房是RecursiveIteratorIteratorRecursiveArrayIterator

+0

问题是所有节点不会被处理相同。仍然需要开关或其他东西。或者我错过了什么? – 2010-06-22 20:57:20

+0

您能提供一个您期望对节点做什么的例子,以便我们更好地理解您正在尝试完成的任务吗? – 2010-06-22 21:18:46

+0

我正在尝试重构树步行者(如下所示:http://github.com/jakubkulhan/phpeg/blob/master/lib/phpgen.php#L506,http://github.com/jakubkulhan/phpeg/blob /master/lib/phpgen.php#L551,http://github.com/jakubkulhan/phpeg/blob/master/lib/phpgen.php#L195以及下面以'g'开头的方法)。我想让它们分开(单独的类/函数)并使用相同的语言结构。 – 2010-06-23 13:44:38

0

我建议这个库:https://packagist.org/packages/lukascivil/treewalker

TreeWalker是一个简单的小图书馆,这将有助于你与结构的操作速度工作,PHP

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