2010-06-22 4 views
1

J'ai des arbres comme celui-ci:La façon la plus élégante de marcher arbres en PHP

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

Chaque noeud est un tableau, le type de noeud est le premier élément et d'autres éléments sont les arguments de noeud (ils peuvent être la liste d'autres noeuds, un seul noeud, une certaine valeur etc., le noeud ne peut pas avoir d'argument, un argument ou plusieurs arguments). D'après vous, quelle est la façon la plus élégante de marcher sur ces types d'arbres, selon vous?

je suis venu avec deux possibilités:

1) en utilisant la déclaration 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; 
    } 
} 

objet 2) avec la méthode pour chaque type de noeud

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

Ou proposez-vous encore plus élégant façon de marcher les arbres? J'ai aussi considéré les nœuds comme des objets et à la place des marcheurs d'arbres séparés, chaque nœud aurait des méthodes pour se promener à l'intérieur. Cependant, je pense que cela rendra le code plus difficile à maintenir, car certaines parties du code des marcheurs seront placées dans des endroits différents et il sera plus difficile d'utiliser le même code pour plusieurs nœuds.

Répondre

0

Je combiné les deux sens et DSL créé:

A ($subnodes) { 
    $ret = ''; 
    foreach ($subnodes as $subnode) { 
     $ret .= WALK($subnode); 
    } 

    return $ret; 
} 
B ($n) { /*...*/ } 
C ($n) { /*...*/ } 
D ($subnode) { /*...*/ } 
E() { /*...*/ } 
F() { /*...*/ } 
G() { /*...*/ } 
H ($n) { /*...*/ } 

qui est traduit en PHP.

3
+0

Le problème est tous les nœuds ne seront pas traités de la même. Il y aura toujours besoin de commutateur ou de quelque chose. Ou est-ce que je manque quelque chose? –

+0

@Jak La traversée elle-même est indépendante de ce que les structures de données, tant qu'elles sont itérables. Si vous voulez traiter les éléments différemment, oui, vous aurez toujours besoin d'une instruction switch ou vous pouvez utiliser des objets à la place des tableaux et tirer parti de la répartition dynamique. – Artefacto

+0

Comme je l'ai écrit dans ma question, j'ai considéré les objets et je pense qu'ils seraient plus de mal que de bien. –

2

Je pense que la simplicité est élégante.

Inutile de réinventer la roue! PHP vient équipé SPL (Standard PHP Library) qui offre plusieurs Iterators qui peut faire tout le travail pour vous.

Quelques de consulter serait RecursiveIteratorIterator et RecursiveArrayIterator

+0

Le problème est que tous les nœuds ne seront pas traités de la même manière. Il y aura toujours besoin de commutateur ou de quelque chose. Ou est-ce que je manque quelque chose? –

+0

Pouvez-vous donner un exemple de ce que vous attendez des nœuds afin que nous comprenions mieux ce que vous essayez d'accomplir? –

+0

J'essaie de refactoriser les marcheurs d'arbres (comme ceux-ci: 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 et les méthodes suivantes commençant par 'g') dans mon générateur PEG. Je veux les séparer (classe/fonction séparée) et utiliser les mêmes constructions de langage. –

0

Je recommande cette bibliothèque: https://packagist.org/packages/lukascivil/treewalker

TreeWalker est un simple et une petite bibliothèque qui vous aidera à travailler plus rapidement grâce à la manipulation des structures en PHP

  • getdiff() - Obtenez la différence JSON
  • walker() - Modifier json (récursivement)
  • structMerge() - Joint deux structures
  • createDynamicallyObjects() - Créer imbriqué Structure par touches dynamiques
  • getDynamicallyValue() - Dynamiquement obtenir une propriété structure
  • setDynamicallyValue() - accès Dynamiquement une propriété de structure pour définir une valeur
Questions connexes