I have a foreach that instances several kind of classes and this must be nested. They all extends of the same Abstract class.
I don't need to handle any specific case but all the cases.
How should I handle this nesting? I was thinking about defining a function in the class that does the foreach, or maybe in the Parent
class, that have all this cases defined inside.
<?php
class Parent
{
private $childs = [];
function nest($child)
{
$this->childs[] = $child;
}
}
// There is different types of A that are nested according to its type.
$A1 = class A extends Parent { $type = 1 }
$A2 = class A extends Parent { $type = 2 }
$B = class B extends Parent {}
$A3 = class A extends Parent { $type = 2 }
$C = class C extends Parent {}
// foreach ([$A1, $A2, $B, $A3, $C])
// $A1->nest($A2);
But $A1
can not be nested, $A2
can only be nested by $A1
, $B
can be nested by $A1
and $A2
but should be nested by $A2 because it's the previous object that can nest it, $A3
should be nested to $A1
, etc.
// expected output of the example
object(A)#1 (2) {
["type"]=>
int(1)
["childs":"Parent":private]=>
array(2) {
[0]=>
object(A)#2 (2) {
["type"]=>
int(2)
["childs":"Parent":private]=>
array(1) {
[0]=>
object(B)#3 (2) {
["childs":"Parent":private]=>
array(0) {
}
}
}
}
[1]=>
object(A)#4 (2) {
["type"]=>
int(2)
["childs":"Parent":private]=>
array(1) {
[0]=>
object(C)#5 (1) {
["childs":"Parent":private]=>
array(0) {
}
}
}
}
}
}
<?php
$numbers = [1, 2, 3, 2, 4];
class Number
{
private $biggers = [];
public function addBigger($number)
{
$this->biggers[] = $number;
}
}
class One extends Number{ private $value = 1; }
class Two extends Number{ private $value = 2; }
class Three extends Number{ private $value = 3; }
class Four extends Number{ private $value = 4; }
foreach ($numbers as $number) {
// Algorithm
}
Expected output:
object(One)#1 (2) {
["value":"One":private]=>
int(1)
["biggers":"Number":private]=>
array(2) {
[0]=>
object(Two)#2 (2) {
["value":"Two":private]=>
int(2)
["biggers":"Number":private]=>
array(1) {
[0]=>
object(Three)#3 (2) {
["value":"Three":private]=>
int(3)
["biggers":"Number":private]=>
array(0) {
}
}
}
}
[1]=>
object(Two)#4 (2) {
["value":"Two":private]=>
int(2)
["biggers":"Number":private]=>
array(1) {
[0]=>
object(Four)#5 (2) {
["value":"Four":private]=>
int(4)
["biggers":"Number":private]=>
array(0) {
}
}
}
}
}
}
What you need is a RecursiveIterator
.
You have to implement your own RecursiveIterator
:
class RecursiveContainerIterator extends IteratorIterator implements RecursiveIterator {
public function getChildren() {
if (is_array($this->current())) {
return new RecursiveArrayIterator($this->current());
} else if ($this->current() instanceof IteratorAggregate) {
return $this->current()->getIterator();
} else {
throw new InvalidArgumentException('');
}
}
public function hasChildren() {
return is_array($this->current()) || $this->current() instanceof Traversable;
}
}
class Container implements IteratorAggregate {
private $children;
public function __construct() {
$this->children = $children = new ArrayObject();
}
public function addChild($child) {
$this->children->append($child);
}
public function getChildren() {
return $this->children;
}
public function getIterator() {
return new RecursiveContainerIterator($this->children);
}
}
$parent = new Container();
$child1 = new Container();
$child2 = new Container();
$grandChild1 = new Container();
$grandChild2 = new Container();
$grandChild3 = new Container();
$grandChild4 = new Container();
$parent->addChild($child1);
$parent->addChild($child2);
$parent->addChild(array(5, 6));
$child1->addChild($grandChild1);
$child1->addChild($grandChild2);
$child2->addChild($grandChild3);
$child2->addChild($grandChild4);
$grandChild1->addChild(1);
$grandChild2->addChild(2);
$grandChild3->addChild(3);
$grandChild3->addChild(4);
foreach (new RecursiveIteratorIterator($parent, RecursiveIteratorIterator::LEAVES_ONLY) as $child) {
var_dump($child);
}
Will output:
int(1) int(2) int(3) int(4) int(5) int(6)
If you need to handle the object itself and not only the leaves, you can use the RecursiveIteratorIterator::SELF_FIRST
flag.
You mean something like that:
$objectArray[] = $A1;
$objectArray[] = $A2;
$objectArray[] = $B;
$objectArray[] = $A3;
$objectArray[] = $C;
foreach($objectArray as $obj){
if(isset($obj->type)){
//type is defined
}else{
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.