何でも使えるツリー構造を定義する

いろいろな場面でツリー構造が必要になるので(たとえばACL機能、ユーザーファイル保存機能etc...)ツリー構造クラスを作った。

class TreeNode{
	var $parent;
	var $children = array();
	var $name;
	var $object;
	
	public function __construct($name = ""){
		$this->name = $name;
	}
	public function appendChild(TreeNode $node){
		$this->children[$node->name] = $node;
		$node->parent = $this;
	}
	public function removeChilde(TreeNode $node){
		unset($this->children[$node->name]);
		$node->parent = null;
	}
	/**
	 * このオブジェクトが指定ノードの先祖かどうか
	 * @param unknown_type $node
	 * @return unknown_type
	 */
	public function isAncestorOf($node){
		$result = false;
		$p = $node->parent;
		while($p != null){	
			if($this->name == $p->name){
				$result = true;
				break;
			}
			$p = $p->parent;
		}
		return $result;
	}
	/**
	 * このオブジェクトが指定ノードの子孫かどうか
	 * @param unknown_type $node
	 * @return unknown_type
	 */
	public function isDescendantOf($node){
		return $node->isAncestorOf($this);
	}
	public function pathString(){
		$path = $this->path();
		$result =join("/",$path);
		
		return $result;
	}
	
	public function path(){
		$result = array($this->name);
		
		$p = $this->parent;
		while($p != null){
			$result[] = $p->name;
			$p = $p->parent;
		}
		return array_reverse($result);
	}
	public function find($path = array()){
		$target = null;
		$count = count($path);
		$current = $this;
		for($depth = 0;$depth < $count;$depth++){
			//現在のノードの子供に対象パスが見つかったらその子供を次のノードに設定する
			if(array_key_exists($path[$depth],$current->children)){
				$current = $current->children[$path[$depth]];
				//現在のノードを発見
				$target = $current;
				continue;
			}
			//見つからない
			break;
		}
		return $target;
	}
}

データの追加はこんな感じ

               $tree = new TreeNode(""); //root node
               $node1 = new TreeNode("node1");
               $tree->appendChild($node1);
               $node2 = new TreeNode("node2");
               $tree->appendChild($node2);
               $node3 = new TreeNode("node3");
               $tree->appendChild($node3);
               
               $node1_1 = new TreeNode("node1_1");
               $node1->appendChild($node1_1);
               $node1_2 = new TreeNode("node1_2");
               $node1->appendChild($node1_2);
               $node1_3 = new TreeNode("node1_3");
               $node1->appendChild($node1_3);
               $node1_4 = new TreeNode("node1_4");
               $node1->appendChild($node1_4);
                      
               $node2_1 = new TreeNode("node2_1");
               $node2->appendChild($node2_1);
               $node2_2 = new TreeNode("node2_2");
               $node2->appendChild($node2_2);
               $node2_3 = new TreeNode("node2_3");
               $node2->appendChild($node2_3);
                      
               $node2_1_1 = new TreeNode("node2_1_1");
               $node2_1->appendChild($node2_1_1);
               $node2_1_2 = new TreeNode("node2_1_2");
               $node2_1->appendChild($node2_1_2);
               $node2_1_3 = new TreeNode("node2_1_3");
               $node2_1->appendChild($node2_1_3);

この結果はこんな感じ

node1 : Array
  node1_1 : Array
    node1_2 : Array
    node1_3 : Array
    node1_4 : Array
  node2 : Array
    node2_1 : Array
      node2_1_1 : Array
      node2_1_2 : Array
      node2_1_3 : Array
    node2_2 : Array
    node2_3 : Array
  node3 : Array

特定ノードを探すなら

$result = $tree->find(array("node2","node2_1","node2_1_1");
//$node2_1_1が見つかる

特定ノード以下から探すなら

$result = $node2_1->find(array("node2_1_1");
//$node2_1_1が見つかる

用はxpath見たいな感じで、現在ノード以下でその名前を持ったノードを探す、という。
path()で対象ノードの「パス」を配列で返し、pathString()で「パス」をスラッシュ区切りで返す。
たぶんC#でもjavascriptでもActionScriptでも同じに書けるはず。

データのロード、セーブは別途。