arr)){ $this->arr[$cur] = array(); } $insert= false; $this->visitNode($path,function ($name,&$node)use(&$insert,&$left,$value,$replace_exits, &$replaced){ $cur = array_shift($left); if($cur === null){ if(array_key_exists('value',$node)){//是否已存在 if(!$replace_exits){ return false; } $replaced = $node['value']; } $node['value'] = $value; $insert = true; return false;//停止遍历 }else{ if(!array_key_exists('next',$node)){ $node['next'] = array(); } if(!array_key_exists($cur,$node['next'])){ $node['next'][$cur]= array(); } } return true; }, true); return $insert; } /** * 删除一个路径下的所有节点 * @param array $path * @return boolean */ public function erase(array $path){ if(count($path)==0){ return false; } $size = count($path); $key = $path[$size-1]; if($size ==1){ if(array_key_exists($key, $this->arr)){ unset($this->arr[$key]); return true; } return false; } $i = 0; $res = false; $full = $this->visitNode($path,function ($name,&$node)use(&$i,$size,$key,&$res){ if(++$i == $size-1){ if(isset($node['next']) && isset($node['next'][$key])){ unset($node['next'][$key]); $res = true; } return false; } return true; }, true); return $res; } /** * 遍历路径 * @param array $path * @return boolean 全部遍历完返回true,否则返回false */ public function visit( $path ,$vistor, $exact_match=false){ return $this->visitNode($path,function ($name,$node)use($vistor){ return $vistor($name,array_key_exists('value',$node)?$node['value']:null); }, $exact_match); } /** * 查找指定路径的节点 * @param array $path * @param boolean $exact_match 是否精确匹配,如果是,则通配符被认为与其他值不同 * @return 返回节点的值, 或者null */ public function find(array $path, $exact_match=false){ $found = null; $full = $this->visitNode($path,function ($name,$node)use(&$found){ $found = array_key_exists('value',$node)?$node['value']:null; return true; }, $exact_match); return $full?$found:null; } /** * 查找指定路径的节点 * @param array $path * @param boolean $exact_match 是否精确匹配,如果是,则通配符被认为与其他值不同 * @param boolean $all_req_paths 是否要求查询路径的所有元素都必须遍历到 * @param boolean $all_paths 是否 * @return 返回节点的, 或者null */ public function findNode(array $path, $exact_match=false, $all_req_paths=false){ $found = null; $full = $this->visitNode($path,function ($name,$node)use(&$found){ $found = $node; return true; }, $exact_match, $all_req_paths); return $full?$found:null; } /** * 遍历路径 * @param array $path * @param boolean $exact_match 是否精确匹配,如果是,则通配符被认为与其他值不同 * @param boolean $all_req_paths 是否要求查询路径的所有元素都必须遍历到 * @return boolean 变量完成返回true,遍历未完成时终止返回false */ private function visitNode( $path, $vistor, $exact_match=false, $all_req_paths=false){ assert(count($path)); $pos = &$this->arr; $next = &$pos; foreach ($path as $i){ if(is_null($next)) { return !$all_req_paths; } if(!array_key_exists($i, $next)){ if($exact_match){ return false; } if($i == self::$end){ return false; } //不要求完全匹配, 尝试匹配通配符 if(!array_key_exists(self::$wildcard, $next)){ return false; } $pos = &$next[self::$wildcard]; }else{ $pos = &$next[$i]; } if(!$vistor($i,$pos)){ return false; } if(array_key_exists('next',$pos)){ $next = &$pos['next']; }else{ $nul = null; $next = &$nul; //$next = null 会导致引用的对象被赋值,而不是next被赋值 } } return true; } /** * 树打平输出成数组 * @return array */ public function export(){ $res=array(); self::treeToArray($this->arr, $res); return $res; } /** * * @param array $tree * @param array $res * @return void */ static private function treeToArray($tree, &$res){ foreach ($tree as $name=>$node){ if($node === null){ continue; } if( isset($node['value']) ){ $res[] = array(array($name), $node['value']); } if( isset($node['next']) ){ $tmp = array(); self::treeToArray($node['next'], $tmp); foreach ($tmp as $v){ array_unshift($v[0], $name); $res[] = array($v[0], $v[1]); } } } } private $arr=array(); static public $end="\n"; static public $wildcard='*'; }