You cannot do all this in one array() . You can customize these trees, but it takes several lines of code to create more complex graphs with multiple parents and other relationships.
This will help a lot if you throw OO. Let me create a Person class to help manage relationships. In fact, we have people and their relationships with other people, so we will start there.
Person class
I think everyone has a lot of relationships. This array will first be indexed by type of relationship, such as "parents" or "children." Each entry will be an array of Person s.
class Person { var $name, $relations; function __construct($name) { $this->name = $name; $this->relations = array(); } function addRelation($type, $person) { if (!isset($this->relations[$type])) { $this->relations[$type] = array(); } $this->relations[$type][] = $person; } // Looks up multiple relations, for example "parents". function getRelations($type) { if (!isset($this->relations[$type])) { return array(); } return $this->relations[$type]; } // Looks up a single relation, for example "spouse". function getRelation($type) { $relations = $this->getRelations($type); return empty($relations) ? null : $relations[0]; } function __toString() { return $this->name; }
Friendly Adders and Recipients
With the above as a basis, we can then add some more friendly method names. To illustrate, we will process the parent / child and spouse relationships.
function addParents($mom, $dad) { $mom->addChild($this); $dad->addChild($this); } function addChild($child) { $this ->addRelation('children', $child); $child->addRelation('parents', $this); } function addSpouse($spouse) { $this ->addRelation('spouse', $spouse); $spouse->addRelation('spouse', $this); } function getParents () { return $this->getRelations('parents'); } function getChildren() { return $this->getRelations('children'); } function getSpouse () { return $this->getRelation ('spouse'); } }
Making people
Now we can create a couple of people and establish their relationship. Let Billy and his parents John and Jane try it.
$john = new Person('John'); $jane = new Person('Jane'); $billy = new Person('Billy'); $john ->addSpouse ($jane); $billy->addParents($jane, $john);
And we can check their relationship like this:
echo "John is married to " . $john->getSpouse() . ".\n"; echo "Billy parents are " . implode(" and ", $billy->getParents()) . ".\n";
Output:
John is married to Jane.
Billy's parents are Jane and John.
Display family tree
We can cross the chart recursively if it grows. Here is an example of a tree function that displays a rudimentary family tree. I added Sarah, her husband Mike and their son Bobby to the mix.
$john = new Person('John'); $jane = new Person('Jane'); $sara = new Person('Sara'); $mike = new Person('Mike'); $bobby = new Person('Bobby'); $billy = new Person('Billy'); $john ->addSpouse ($jane); $sara ->addParents($jane, $john); $sara ->addSpouse ($mike); $bobby->addParents($sara, $mike); $billy->addParents($jane, $john); function displayFamilyTree($root, $prefix = "") { $parents = array($root); if ($root->getSpouse() != null) { $parents[] = $root->getSpouse(); } echo $prefix . implode(" & ", $parents) . "\n"; foreach ($root->getChildren() as $child) { displayFamilyTree($child, "....$prefix"); } } displayFamilyTree($john);
Output:
John and Jane
.... Sarah and Mike
........ Bobby
.... Billy
Edit: Here is the @Wrikken comment below to reproduce:
About it really. IMHO adds from the date to each relationship though (maybe NULL without end). There are divorces, as well as adoptions, etc. Also: I would add inverse types and "flip back" to the addRelation() function:
function addRelation($type, $person, $reverseType, $pingback = false) { if (!isset($this->relations[$type])) { $this->relations[$type] = array(); } if (!in_array($person, $this->relations[$type], true)) { $this->relations[$type][] = $person; } if (!$pingback) { $person->addRelation($reverseType, $this, $type, true); } }