2010-06-22 65 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() - 動態訪問的結構屬性來設置值