如何在Php中循环循环元素?

如何在Php中循环循环元素?,php,recursion,tree,while-loop,Php,Recursion,Tree,While Loop,我正在创建一个带有parentid的类别树结构,可以通过以下方式从子级调用: ID | Name | ParentID 1 1 0 2 2 1 3 3 2 4 4 1 因此: 1 = 1 2 = 1 -> 2 3 = 1 -> 2 -> 3 4 = 1 -> 4 这意味着3是2的孩子,而是1的孩子 当我试图得到这个想法(用->来显示设置了什么关系)时,我只得到了第二级(1->2),而没有到第三级(1->2

我正在创建一个带有parentid的类别树结构,可以通过以下方式从子级调用:

ID | Name | ParentID
1    1      0
2    2      1
3    3      2
4    4      1
因此:

1 = 1
2 = 1 -> 2
3 = 1 -> 2 -> 3
4 = 1 -> 4
这意味着3是2的孩子,而是1的孩子

当我试图得到这个想法(用->来显示设置了什么关系)时,我只得到了第二级(1->2),而没有到第三级(1->2->3),因为我使用了循环函数

//put all ID's in an array
while ($row2 = $connector->fetchArray($result2)){
 $id = $row2['ID'];
 $parents[$id] = $row2['name'];
}

// show the tree-structure
while ($row = $connector->fetchArray($result)){
    if($row['parentid']!=0)echo $parents[$row['parentid']].' -> ';
    echo $row['name'].' -    ';
    echo '<br>';
}

与其让PHP将项目组织成一棵树,为什么不让数据库为您这样做呢?我发现这是非常好的,例子几乎与你的相同


编辑


使用邻接模型获取完整树的SQL并不理想。正如本文所解释的,即使是很小的层次结构,也需要相当多的连接。您不可能使用嵌套集方法吗?不管层次结构的大小,SQL都保持不变,插入和删除也应该不会很困难。

与其让PHP将项目组织到树中,为什么不让数据库为您这样做呢?我发现这是非常好的,例子几乎与你的相同


编辑


使用邻接模型获取完整树的SQL并不理想。正如本文所解释的,即使是很小的层次结构,也需要相当多的连接。您不可能使用嵌套集方法吗?不管层次结构的大小,SQL都保持不变,插入和删除也应该不会很困难。

如果您真的想使用父ID进行层次结构(仅适用于少量项目/层次结构)

我稍微修改了您的代码(我没有测试它,所以可能有一些语法错误):

//将所有记录集放在一个数组中以保存第二个查询
而($row2=$connector->fetchArray($result2)){
$id=$row2['id'];
$parents[$id]=数组('name'=>$row2['name'],'parent'=>$row2['parentid']);
}
//显示树结构
foreach($id=>$row的父对象){
$pid=$row['parentid'];
而($pid!=0){//遍历所有父对象,直到到达顶部
echo$parents[$pid]['name'].-';
$pid=$parents[$pid]['parentid'];
}
echo$parents[$id]['name'].-';
回声“
”; }
要回答您的评论:

$parents = array();
$parents[2] = array('ID'=>2,'name'=>'General','parentid'=>0); 
$parents[3] = array('ID'=>3,'name'=>'Gadgets','parentid'=>2); 
$parents[4] = array('ID'=>4,'name'=>'iPhone','parentid'=>3); 

foreach ($parents as $id => $row){
  $pid=$id;
  $arrTmp= array();
  do {      // iterate through all parents until top is reached
    $arrTmp[]=$pid;
    $pid = $parents[$pid]['parentid'];
  }while ($pid != 0);
    $arrTmp = array_reverse($arrTmp);
  foreach($arrTmp as $id){
    echo $parents[$id]['name'].' -&gt; ';
    }
  echo '<br>';
}
$parents=array();
$parents[2]=数组('ID'=>2,'name'=>General','parentid'=>0);
$parents[3]=数组('ID'=>3,'name'=>Gadgets','parentid'=>2);
$parents[4]=数组('ID'=>4,'name'=>iPhone','parentid'=>3);
foreach($id=>$row的父对象){
$pid=$id;
$arrTmp=array();
执行{//遍历所有父级,直到到达顶部
$arrTmp[]=$pid;
$pid=$parents[$pid]['parentid'];
}而($pid!=0);
$arrTmp=阵列_反向($arrTmp);
foreach($arrTmp作为$id){
echo$parents[$id]['name'].-';
}
回声“
”; }
打印出:

一般->

常规->小工具->

常规->小工具->iPhone->


如果您确实希望使用父ID进行层次结构(仅适用于少量项目/层次结构)

我稍微修改了您的代码(我没有测试它,所以可能有一些语法错误):

//将所有记录集放在一个数组中以保存第二个查询
而($row2=$connector->fetchArray($result2)){
$id=$row2['id'];
$parents[$id]=数组('name'=>$row2['name'],'parent'=>$row2['parentid']);
}
//显示树结构
foreach($id=>$row的父对象){
$pid=$row['parentid'];
而($pid!=0){//遍历所有父对象,直到到达顶部
echo$parents[$pid]['name'].-';
$pid=$parents[$pid]['parentid'];
}
echo$parents[$id]['name'].-';
回声“
”; }
要回答您的评论:

$parents = array();
$parents[2] = array('ID'=>2,'name'=>'General','parentid'=>0); 
$parents[3] = array('ID'=>3,'name'=>'Gadgets','parentid'=>2); 
$parents[4] = array('ID'=>4,'name'=>'iPhone','parentid'=>3); 

foreach ($parents as $id => $row){
  $pid=$id;
  $arrTmp= array();
  do {      // iterate through all parents until top is reached
    $arrTmp[]=$pid;
    $pid = $parents[$pid]['parentid'];
  }while ($pid != 0);
    $arrTmp = array_reverse($arrTmp);
  foreach($arrTmp as $id){
    echo $parents[$id]['name'].' -&gt; ';
    }
  echo '<br>';
}
$parents=array();
$parents[2]=数组('ID'=>2,'name'=>General','parentid'=>0);
$parents[3]=数组('ID'=>3,'name'=>Gadgets','parentid'=>2);
$parents[4]=数组('ID'=>4,'name'=>iPhone','parentid'=>3);
foreach($id=>$row的父对象){
$pid=$id;
$arrTmp=array();
执行{//遍历所有父级,直到到达顶部
$arrTmp[]=$pid;
$pid=$parents[$pid]['parentid'];
}而($pid!=0);
$arrTmp=阵列_反向($arrTmp);
foreach($arrTmp作为$id){
echo$parents[$id]['name'].-';
}
回声“
”; }
打印出:

一般->

常规->小工具->

常规->小工具->iPhone->


使用OOP可能更容易。只需按parentId对查询进行排序

注意:listChildren方法和底部的打印输出仅用于显示它已正确列出。我没有解释这个问题,显示是重要的

class Element {
    public $id;
    public $name;
    public $parent = null;
    public $children = array();

    public function __construct($id, $name)
    {
        $this->id = $id;
        $this->name = $name;
    }

    public function addChild($element)
    {
        $this->children[$element->id] = $element;
        $element->setParent($this);
    }

    public function setParent($element)
    {
        $this->parent = $element;
    }

    public function hasChildren()
    {
        return !empty($this->children);
    }

    public function listChildren()
    {
        if (empty($this->children)) {
            return null;
        }

        $out = array();
        foreach ($this->children as $child) {
            $data = $child->id . ':' . $child->name;
            $subChildren = $child->listChildren();
            if ($subChildren !== null) {
                $data .= '[' . $subChildren . ']';
            }
            $out[] = $data;
        }
        return implode(',', $out);
    }
}

$elements = array();
$noParents = array();
while ($row = $connector->fetchArray($result)) {
    $elements[$row['id']] = $element = new Element($row['id'], $row['name']);

    if (isset($elements[$row['parent']])) {
        $elements[$row['parent']]->addChild($element);
    } else {
        $noParents[] = $element;
    }
}

foreach ($noParents as $element) {
    if ($element->hasChildren()) {
        echo "Element {$element->id} has children {$element->listChildren()}.\n";
    } else {
        echo "Element {$element->id} has no children.\n";
    }
}

使用OOP可能更容易。只需按parentId对查询进行排序

注意:listChildren方法和底部的打印输出仅用于显示它已正确列出。我没有解释这个问题,显示是重要的

class Element {
    public $id;
    public $name;
    public $parent = null;
    public $children = array();

    public function __construct($id, $name)
    {
        $this->id = $id;
        $this->name = $name;
    }

    public function addChild($element)
    {
        $this->children[$element->id] = $element;
        $element->setParent($this);
    }

    public function setParent($element)
    {
        $this->parent = $element;
    }

    public function hasChildren()
    {
        return !empty($this->children);
    }

    public function listChildren()
    {
        if (empty($this->children)) {
            return null;
        }

        $out = array();
        foreach ($this->children as $child) {
            $data = $child->id . ':' . $child->name;
            $subChildren = $child->listChildren();
            if ($subChildren !== null) {
                $data .= '[' . $subChildren . ']';
            }
            $out[] = $data;
        }
        return implode(',', $out);
    }
}

$elements = array();
$noParents = array();
while ($row = $connector->fetchArray($result)) {
    $elements[$row['id']] = $element = new Element($row['id'], $row['name']);

    if (isset($elements[$row['parent']])) {
        $elements[$row['parent']]->addChild($element);
    } else {
        $noParents[] = $element;
    }
}

foreach ($noParents as $element) {
    if ($element->hasChildren()) {
        echo "Element {$element->id} has children {$element->listChildren()}.\n";
    } else {
        echo "Element {$element->id} has no children.\n";
    }
}

如果使用PostgreSQL作为数据库,则可以使用()函数创建记录集:

SELECT * 
FROM connectby('tableName', 'id', 'parent_id') 
    AS t(keyid text, parent_keyid text, level int);

我喜欢这个函数,并且在我的代码中一直使用它。它可以非常快速地完成一些非常强大的任务,您不必像(邻接模型)那样维护左/右值。

如果您使用PostgreSQL作为数据库,您可以使用()函数创建记录集:

SELECT * 
FROM connectby('tableName', 'id', 'parent_id') 
    AS t(keyid text, parent_keyid text, level int);

我喜欢这个函数,并且在我的代码中一直使用它。它可以非常快速地完成一些非常强大的任务,而且您不必像(邻接模型)那样维护左/右值。

嘿,Peter,这需要在SQL中进行大量的添加、删除或更改工作。无法使用页面上的第一个示例,因为每次添加都必须添加一个左连接。第二个例子太复杂了,无法简单地使用。但是,有没有一种方法可以让SQL以某种方式找到父级和缩进?例如,我可以用php创建一个类似JSON的数组吗?带孩子的obj