相信很多 php 开发者都遇到过这样的场景:你需要在一个数据库中存储具有层级关系的数据,比如一个多级分类系统、一个文件目录结构,或者一个组织内的部门层级。最直观的实现方式,莫过于在每个记录中添加一个
parent_id
这种方法在插入和查询直接父子关系时非常简单。然而,一旦你需要:
传统的
parent_id
那么,有没有一种更高效、更优雅的方式来处理这些树形数据呢?答案是肯定的,那就是“嵌套集合模型”(Nested Set Model),以及我们今天要介绍的
previousnext/nested-set
previousnext/nested-set
嵌套集合模型是一种在关系型数据库中存储树形结构的强大方法。它通过为每个节点分配一对“左值”(
lft
rgt
lft
rgt
lft
rgt
lft
rgt
立即学习“PHP免费学习笔记(深入)”;
这种模型最大的优势在于,查询一个节点的所有子孙节点或祖先节点,不再需要复杂的递归,而只需要简单的范围查询,效率极高。
previousnext/nested-set
要开始使用
previousnext/nested-set
打开你的终端,进入项目根目录,然后执行以下命令:
<pre class="brush:php;toolbar:false;">composer require previousnext/nested-set
Composer 会自动下载
previousnext/nested-set
vendor/autoload.php
<pre class="brush:php;toolbar:false;">require 'vendor/autoload.php'; // ... 你的代码
通过 Composer,你无需手动下载、解压和管理库文件,一切都变得自动化且版本可控。
previousnext/nested-set
接下来,我们通过一个简单的例子来看看
previousnext/nested-set
1. 数据库连接与表结构创建
previousnext/nested-set
<pre class="brush:php;toolbar:false;">use Doctrine\DBAL\DriverManager;
use PNX\NestedSet\DbalNestedSetSchema;
use PNX\NestedSet\DbalNestedSet;
use PNX\NestedSet\NodeKey;
// 假设你已经有一个数据库连接配置
$connectionParams = [
'url' => 'mysql://user:password@localhost/database_name',
];
$connection = DriverManager::getConnection($connectionParams);
// 创建嵌套集合表,表名为 'my_tree'
$schema = new DbalNestedSetSchema($connection, 'my_tree');
$schema->create(); // 这将创建包含 lft, rgt, depth 等字段的表2. 初始化嵌套集合客户端
创建
DbalNestedSet
<pre class="brush:php;toolbar:false;">$nestedSet = new DbalNestedSet($connection, 'my_tree');
3. 添加节点
NodeKey
<pre class="brush:php;toolbar:false;">// 添加一个根节点:A
$nodeKeyA = new NodeKey('A', 1);
$rootNodeA = $nestedSet->addRootNode($nodeKeyA);
echo "Added root node: A\n";
// 在 A 下添加子节点:B
$nodeKeyB = new NodeKey('B', 1);
$nodeB = $nestedSet->addNodeBelow($rootNodeA, $nodeKeyB);
echo "Added node B below A\n";
// 在 B 下添加子节点:C
$nodeKeyC = new NodeKey('C', 1);
$nodeC = $nestedSet->addNodeBelow($nodeB, $nodeKeyC);
echo "Added node C below B\n";
// 在 A 下添加另一个子节点:D (与 B 同级)
$nodeKeyD = new NodeKey('D', 1);
$nodeD = $nestedSet->addNodeBelow($rootNodeA, $nodeKeyD);
echo "Added node D below A\n";
/*
树结构示意:
A
├── B
│ └── C
└── D
*/4. 查询节点
现在,最激动人心的部分来了——查询!
<pre class="brush:php;toolbar:false;">// 查找节点 A 的所有子孙节点
echo "\nDescendants of A:\n";
$descendantsOfA = $nestedSet->findDescendants($nodeKeyA);
foreach ($descendantsOfA as $node) {
echo " - " . $node->getKey()->getId() . "\n";
}
// 输出:B, C, D (顺序可能不同,但都会包含)
// 查找节点 C 的所有祖先节点
echo "\nAncestors of C:\n";
$ancestorsOfC = $nestedSet->findAncestors($nodeKeyC);
foreach ($ancestorsOfC as $node) {
echo " - " . $node->getKey()->getId() . "\n";
}
// 输出:A, B (通常按层级向上排序)正如你所见,查询子孙和祖先节点变得异常简单,你只需要提供目标节点的
NodeKey
使用
previousnext/nested-set
WHERE lft BETWEEN X AND Y
parent_id
在实际应用中,
previousnext/nested-set
告别那些让人头疼的递归查询和性能瓶颈吧!
previousnext/nested-set
previousnext/nested-set
以上就是告别递归查询噩梦:如何使用previousnext/nested-set和Composer优雅管理PHP树形数据的详细内容,更多请关注php中文网其它相关文章!
PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号