`
xuebingnanmm
  • 浏览: 172536 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

PHP无限分类的原理

    博客分类:
  • PHP
阅读更多
以下是无限分类的分析原理,总结出来的是效率比较慢,功能实现了,如果有更好的方法 请评论下。

 ·什么是无限分类呢?就像windows下新建一个文件夹,在新建的文件夹下又可以新建一个文件夹,这样无限循环下去,无限分类也是这样,父类可以分出它子类,子类又可以分出它的子类,这样一直无限循环下去。

 

·那PHP又是如何实现它的无限分类的呢?如何把它的各个分类一一列出来呢?首先我们假设有这样的一个三级分类,新闻→PHP新闻→PHP6.0出来了。如果我们要查找“PHP6.0出来了”这条新闻,我们先点击新闻,然后再点击PHP新闻就可以查出来了,也就是说我们可以通过祖父类一级一级地往下找,反过来我们只要知道一个子类的父类,就可以把它查找出来了。这样我们在设计数据库时就可以多设计一个父类id的字段就可以实现无限分类的功能了。

 

//我们建一个表"class"
CREATE TABLE `class` (
  `id` int(11) NOT NULL auto_increment COMMENT '分类id',
  `f_id` int(11) NOT NULL COMMENT '父id',
  `name` varchar(25) collate gbk_bin NOT NULL COMMENT '分类名称',
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=gbk COLLATE=gbk_bin AUTO_INCREMENT=1 ;
 
//首先我们往数据库里插入‘新闻’这个大分类,因为‘新闻’是最大分类,上面没有父类了,所以我把它的f_id设置为0。
INSERT INTO `class` (`id`, `f_id`, `name`) VALUES(1, 0, '新闻');   //id这个字段是自动增长的,可以不写值。
 
//然后我们再往数据库里插入‘PHP新闻’这个分类,它的父类‘新闻’的id是1,所以它的f_id设置为1。
INSERT INTO `class` (`id`, `f_id`, `name`) VALUES(2, 1, 'PHP新闻');
 
//然后我们再往数据库里插入‘PHP6.0出来了’这个分类,它的父类‘PHP新闻’的id是2,所以它的f_id设置为2。
INSERT INTO `class` (`id`, `f_id`, `name`) VALUES(3, 2, 'PHP6.0出来了');
 
//同理,我们可以这样一直往下插入分类,也就达到了无限分类。
//我们可以发现插入一个分类的原则关键是找到这个分类的父类的id,然后作为这个分类的f_id字段的值。
//假设要插入跟‘新闻’同一个级别的分类‘技术’,也就是说它也是最大分类,上面没有父类了,那么它的f_id也设置为0;
INSERT INTO `class` (`id`, `f_id`, `name`) VALUES(4, 0, '技术'); 
 
//在‘技术’下面又有一个分类‘PHP技术’,那么我们怎么插入呢,首先找到‘PHP技术’的父类‘技术’的id,然后作为自己的f_id字段的值。
INSERT INTO `class` (`id`, `f_id`, `name`) VALUES(5, 4, 'PHP技术'); 
 
//看到这里,想必大家应该都明白怎么往数据库里插入各个分类了。就不再举例了。

 

我们已经知道如何往数据库里插入各个分类了,那又如何把各个分类罗列出来呢?

 

<?php
header("Content-type:text/html;charset=utf-8"); 
$db=new mysqli("localhost","root","","news_php100") ; //实例化一个数据库连接。使用这个前一定要确保已经加载了mysqli类库,或者用mysql_connect这个方式连接。 
if(mysqli_connect_errno()){
 	echo "链接失败:".mysqli_connect_error();
 	exit(); } 
$db->query("set names utf8");
$result=$db->query("select name from class where f_id=0"); //查找f_id=0的分类,也就是查找每一个大类。
while($row=$result->fetch_assoc()){
      echo $row['name']."<br>";        //这样就把每个大类循环出来了。
}
//同样我们可以把新闻的子类循环出来。
$result=$db->query("select * from class where f_id=1"); //查找f_id=1的分类,也就是查找‘新闻’的子类。
while($row=$result->fetch_assoc()){
      echo $row['name']."
";        //这样就把‘新闻’的子类循环出来了。注意:只是子类,不包括孙子类。
}
//写到这里,我们会发现一个问题,如果这个分类是10级分类,难道我们要写10个循环把它每个子类循环出来?如果是更多级分类呢,这样写显然是不现实的。
//那又有什么办法解决呢?我们可以写一个递归的函数,把f_id作为参数传入,不断循环每一个f_id的值,也就是说把每一个f_id值的子类循环出来。
//首先我们把各个分类的值保存在一个二维数组中,在下面的递归函数里有用。
$result=$db->query("select * from class");
while($row=$result->fetch_assoc()){
     $arr[]=array($row[id],$row[f_id],$row[name]);    //每一行保存一个分类的id,f_id,name的信息。
}

fenlei();

function fenlei($f_id=0){     //$f_id初始化为0,也就是从最大分类开始循环.
    global $arr;   //声明$arr为全局变量才可在函数里引用。
    for($i=0;$i<count($arr);$i++){       //对每个分类进行循环。
           if($arr[$i][1]==$f_id){         //$arr[$i][1]表示第$i+1个分类的f_id的值。开始$f_id=0,也就是把f_id=0的分类输出来。
                 echo $arr[$i][2]."<br>"; //$arr[$i][1]表示第$i+1个分类的name的值。
            fenlei($arr[$i][0]);   //$arr[$i][1]表示第$i+1个分类的id的值。进行递归,也就是把自己的id作为f_id参数把自己的子类再循环出来。
}
}
}
?>

 

真正调试:

--
-- 表的结构 `cms_admin_action`
--

CREATE TABLE IF NOT EXISTS `cms_admin_action` (
  `action_id` int(11) NOT NULL AUTO_INCREMENT,
  `parent_id` int(11) NOT NULL,
  `action_code` text COLLATE utf8_unicode_ci NOT NULL,
  `action_title` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `action` varchar(30) COLLATE utf8_unicode_ci NOT NULL,
  `url` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `sorder` int(3) NOT NULL,
  PRIMARY KEY (`action_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=15 ;

 

 

<?php   
header("Content-type:text/html;charset=utf-8");    

$db=new mysqli("127.0.0.1","root","root","cms") ; 
if(mysqli_connect_errno())
{   
	echo "链接失败:".mysqli_connect_error();   
	exit(); 
}    

$db->query("set names utf8");  

$result=$db->query("select * from cms_admin_action");  
while($row=$result->fetch_assoc())
{   
     $arr[]=array($row['action_id'],$row['parent_id'],$row['action_title']); 
}

fenlei();

function fenlei($f_id=0,$lever=1)
{
	global $arr;
	
	if($f_id == 0) 
		$lever=1;
	else
		$lever +=1;

	for($i=0;$i<count($arr);$i++)
	{
		if($arr[$i][1]==$f_id)
		{
			echo "No.".$lever." Lever:".$arr[$i][2]."<br>"; 
			fenlei($arr[$i][0],$lever);
		}   
	}   
}   
?>  

 

另外一种思路(效果比较高,逻辑处理稍复杂):http://www.w3pop.com/learn/view/p/4/o/0/doc/php_nolimit_class/

 

 

其他的无限分类代码:

 

/**
* author: askie
* blog: http://www.pkphp.com
* 版权: 随便用
* 无限分类
*/
class Tree
{
        public $data=array();
        public $cateArray=array();
        
        function Tree()
        {
               
        }
        function setNode ($id, $parent, $value)
    {
        $parent = $parent?$parent:0;
        $this->data[$id]                = $value;
        $this->cateArray[$id]        = $parent;
    }
    function getChildsTree($id=0)
    {
            $childs=array();
            foreach ($this->cateArray as $child=>$parent)
            {
                    if ($parent==$id)
                    {
                            $childs[$child]=$this->getChildsTree($child);
                    }
                    
            }
            return $childs;
    }
    function getChilds($id=0)
    {
            $childArray=array();
            $childs=$this->getChild($id);
            foreach ($childs as $child)
            {
                    $childArray[]=$child;
                    $childArray=array_merge($childArray,$this->getChilds($child));
            }
            return $childArray;
    }
    function getChild($id)
    {
            $childs=array();
            foreach ($this->cateArray as $child=>$parent)
            {
                    if ($parent==$id)
                    {
                            $childs[$child]=$child;
                    }
            }
            return $childs;
    }
    //单线获取父节点
    function getNodeLever($id)
    {
            $parents=array();
            if (key_exists($this->cateArray[$id],$this->cateArray))
            {
                    $parents[]=$this->cateArray[$id];
                    $parents=array_merge($parents,$this->getNodeLever($this->cateArray[$id]));
            }
            return $parents;
    }
    function getLayer($id,$preStr='|-')
    {
            return str_repeat($preStr,count($this->getNodeLever($id)));
    }
    function getValue ($id)
    {
        return $this->data[$id];
    } // end func
}

/*$Tree = new Tree("请选择分类");
//setNode(目录ID,上级ID,目录名字);
$Tree->setNode(1, 0, '目录1');
$Tree->setNode(2, 1, '目录2');
$Tree->setNode(5, 3, '目录5');
$Tree->setNode(3, 0, '目录3');
$Tree->setNode(4, 2, '目录4');
$Tree->setNode(9, 4, '目录9');
$Tree->setNode(6, 2, '目录6');
$Tree->setNode(7, 2, '目录7');
$Tree->setNode(8, 3, '目录8');

//print_r($Tree->getChildsTree(0));
//print_r($Tree->getChild(0));
//print_r($Tree->getLayer(2));

$category = $Tree->getChilds();

//遍历输出
foreach ($category as $key=>$id)
{
    echo $id.$Tree->getLayer($id, '|-').$Tree->getValue($id)."\n";
}*/

?>

 

分享到:
评论
1 楼 872890971 2011-08-18  
echo "No.".$lever." Lever:".$arr[$i][2]."<br>"; 
怎么用变量调用。

相关推荐

    PHP无限分类的原理.

    PHP无限分类的原理,递归应用的详细讲解1

    PHP无限级分类算法原理及实例演示

    那PHP又是如何实现它的无限分类的呢?如何把它的各个分类一一列出来呢? 首先我们假设有这样的一个三级分类,新闻→PHP新闻→PHP6.0出来了。 如果我们要查找“PHP6.0出来了”这条新闻,我们先点击新闻,然后再点击...

    简单易用的php无限分类树

    php无限分类树原理,简单实用.引用自PHPCHINA版主,七月十五人士也!

    PHP利用递归函数实现无限级分类的方法

    相信很多学php的很多小伙伴都会尝试做一个网上商城作为提升自己技术的一种途径。...无限分类看似”高大上”,实际上原理是非常简单的 。无限分类不仅仅需要代码的巧妙性,也要依托数据库设计的合理性。

    php+mysql实现无限级分类

    主要介绍了php+mysql实现无限级分类,一个php项目需要用到分类,动手制作了一个php无限极分类,感兴趣的小伙伴们可以参考一下

    PHP实现无限级分类(不使用递归)

    1.实现原理 几种常见的实现方法,各有利弊。其中“改进前序遍历树”数据结构,便于输出和查询,但是在移动分类和常规理解上有些复杂。 2.数据结构 &lt;?php $list = array( array('id'=&gt;1, 'fid'=&gt;0, 'title' =&gt;...

    自己前几天写的无限分类类

    ][/url] 这里就不多解释原理了,直接发代码。 PS:这里代码是不能直接使用的,必须结合我的一些其他库类。应该说思想才是最重要的,这里主要提供一种分类的思路。复制代码 代码如下:&lt;? /** — — 表的结构 ...

    夏日文章PHP+MYSQL管理系统 v1.2

    夏日文章CMS管理系统是面向新手用户所开发的一款php+mysql新闻类系统,是由夏日博客独立设计完成,前台页面美观,后台程序精简,整体源码结构非常简洁,可以进行后台独立管理,新闻无限分类,内容页可以生成静态页面...

    SSCMS内容管理系统1.0 build 0622

    稍后还将遵循SEO原理增加站点地图(sitemap)的生成。 10、强大的内容调用首页完全自主设计。 SSCMS分类栏目首页完全自主定义。包括图片新闻,显示是否调用时间,栏目,静态模块的放置位置等等。 11、...

    迅睿CMS免费开源系统-PHP

    4、联动菜单字段,用于无限分类层级显示的数据,例如城市 5、百度地图字段,用于定位地图坐标,坐标范围内筛选数据 6、富文本字段,百度编辑器、百度移动编辑器 7、选项字段,单选字段、多选字段、下拉选择字段 8、...

    dayrui-xunruicms-master.zip

    4、联动菜单字段,用于无限分类层级显示的数据,例如城市 5、百度地图字段,用于定位地图坐标,坐标范围内筛选数据 6、富文本字段,百度编辑器、百度移动编辑器 7、选项字段,单选字段、多选字段、下拉选择字段 ...

    Pluto1_9_9_2.rar

    原理上是可以的,用fastcgi进行,默认情况下,php是9000端口,JSP的tomcat是8080端口,通过c/s模式进行。 但是,这就没有发掘C++Builder的作用,不如直接搭建NginX,Apache,lighttpd+tomcat。通过实践,在Web服务器上...

    迅睿CMS免费开源系统

    1、文本字段,有单行文本、多行文本、文本事件字段2、上传字段,有单文件上传、多文件上传3、日期时间字段,支持自定义年月格式显示4、联动菜单字段,用于无限分类层级显示的数据,例如城市5、百度地图字段,用于...

    MongoDB权威指南(中文版)高清

    856.4.2 例2:网页分类 876.4.3 MongoDB和MapReduce 87第7章 进阶指南 917.1 数据库命令 917.1.1 命令的工作原理 927.1.2 命令参考 937.2 固定集合 957.2.1 属性及用法 967.2.2 创建固定集合 967....

    史上最好传智播客就业班.net培训教程60G 不下会后悔

    传智播客认真钻研教学,对知识进行分类、整理、提炼精华,让学员在短时间内掌握ASP.Net技术。 ASP.Net中有一些技术是有局限性的,传智播客根据这些技术在企业中的实际应用情况进行了调整、补充。比如项目中几乎没有...

Global site tag (gtag.js) - Google Analytics