Skip to content

Instantly share code, notes, and snippets.

@Jeff-Russ
Last active December 5, 2016 05:16
Show Gist options
  • Select an option

  • Save Jeff-Russ/f15aca220e83787309ebd2d62f10d60e to your computer and use it in GitHub Desktop.

Select an option

Save Jeff-Russ/f15aca220e83787309ebd2d62f10d60e to your computer and use it in GitHub Desktop.
<?php
/**
* Node is a smart array object inspired by the Node/Tree data structure and the
* UNIX file system's inodes. Just a UNIX directory has a hidden file called
* '..' in every directory which is a reference to the parent directory, a Node
* object has $node['..'] which is a reference to the parent Node, or itself
* if there is no parent Node meaning the Node is 'root', and it's $node['/']
* element which would also be reference to itself if root.
*
* Basically a Node is an array on steroids but why would you need this? Nodes
* keep everything in reach in any scope without poluting the global namespace.
* You can pass a single Node object into a callback and have it expand itself
* to have access to objects "above" it or "below" it. You could actually have
* an entire piece of software that is just one node object variable with every
* piece of data being array elements and object references contained within it.
*
* There is a '.' key which is the contents of the Node's 'tree' (really just a
* normal array) but it's not directly accessable. The layer of code between
* you and the array ensures that any arrays/node added and removed to the node
* are automatically configured to reflect the changing relationships. For
* example, if you take a node that sits on one node and add it the key of
* another, the old node will be told to unset it and the new node will set it's
* parent and root properties to reflect it's new home. Arrays can be set to be
* converted to full Node objects automatically. Nested Node's can be set not
* be directly re-assignable, only their contents and their keys can be protected.
*
* See the keys on $_ ( $ # ~ ! .. / and . ) to get more info.
*/
class Node implements Serializable, IteratorAggregate, ArrayAccess, Countable
{
protected $_;
public function __construct($array=[], $args=[]) {
$this->_ = array_merge([
'$' =>'', # if nested, key on parent's _['.']
'#' => 0, # distance from root node
'~' => true, # true/false/'shallow' array to node conversion
'!' => 'nodes',# true/false/'nodes' prevent reassignment
'..'=> $this, '/' => $this, '.'=> $array
], $args);
if ( !empty($this->_['.']) ) self::_rConfig($this);
}
public function serialize(){ return serialize($this->_['.']); }
public function unserialize($s_ized) { $this->_['.'] = unserialize($s_ized);}
public function getIterator() { return new ArrayIterator( $this->_['.'] ); }
public function count() { return count( $this->_['.'] ); }
public function length(){ return $this->count(); }
public function offsetExists($key){return array_key_exists($key,$this->_['.']);}
public function eject($key) {return $this->offsetUnset($key);}
public function offsetUnset($key) {
if (array_key_exists($key, $this->_['.'])) {
$v = $this->_['.'][$key];
if (is_a($v, get_class())) {
$v->_['#'] = 0;
$v->_['..']= $node;
$v->_['/'] = $node;
if ( !empty($v->_['.']) ) self::_rConfig($v);
}
unset( $this->_['.'][$key] ); return $v;
}
else return null;
}
public function offsetGet($key)
{
if (ctype_punct($key[0])) {
if (array_key_exists($key,$this->_) && $key!=='.') return $this->_[$key];
elseif ($key==='/?') return $this->_['/']===$this; # is root?
elseif ($key==='..$')return $this->_['..']->_['$'];# parent key
elseif ($key==='/$') return $this->_['/']->_['$']; # root key
elseif ($key==='[n]')return count($this->_['.']); # count
}
return array_key_exists( $key,$this->_['.'] ) ? $this->_['.'][$key] : null;
}
public function offsetSet($key, $val)
{
# modify node properties
if (ctype_punct($key[0])) {
# change key:
if ($key==='$') {
if ($this['/']===$this ) { $this['/'] = $val; return $this; }
if ($this->keyStat($val)) return false;
$parent =& $this->_['..']->_['.'];
if ($parent[$this->_['$']]===$this) unset($parent[$this->_['$']]);
$this->_['$'] = $val;
$parent[$val] = $this;
return $this;
# change parent:
} elseif ($key==='..') {
if ($this->_['..']===$val) return false;
elseif (!is_a($val, get_class())) return false;
else { $this->_['.'][$key] = $val; self::_rConfig($this, $key); }
return $this;
# change protection level:
} elseif ($key==='!') { $this->_['!'] = $val;
# change conversion setting and apply:
} elseif ($key==='~') {
if ($val=null) return $this->_['~']; #getter mode
elseif ($val===$this->_['~']) return $this;
else $this->_['~'] = $val;
if (!empty($this->_['.'])) self::_rConfig($this);
return $this;
}
}
if ( array_key_exists($key, $this->_['.']) ) {
$prev_val = $this->_['.'][$key];
$is_node = is_a($prev_val, get_class());
if ( $this->_['!']!==false ) /* there is at least some protection */ {
# anything but protection being false blocks nodes. true blocks all:
if ($this->_['!']===true || $is_node) return false;
# we can overwrite an array but only if protection is set to 'nodes'
elseif (is_array($prev_val) && $this->_['!']!=='nodes') return false;
# If it was a node we should formally remove it (make it root):
if ($is_node) {
$prev_val->_['#'] = 0;
$prev_val->_['..']= $prev_val;
$prev_val->_['/'] = $prev_val;
if ( !empty($this->_['.'][$key]->_['.']) )
self::_rConfig( $this->_['.'][$key] );
}
}
unset($this->_['.'][$key]);
}
$this->_['.'][$key] = $val;
self::_rConfig($this, $key);
return $prev_val ? $prev_val : $this;
}
public function keyStat($key) { # Returns truthy if assignable, falsy if not.
# null means unset, a boolean means it's a node object. A string means
# it's some other type. Empty strings, false and null are all assignable.
if ( array_key_exists($key, $this->_['.']) ) {
if ($this->_['~']!==false) {
if (is_a($this->_['.'][$key], get_class())) return true;
elseif ($this->_['~']==='nodes') return false;
elseif ($this->_['~']===true) return gettype($this->_['.'][$key]);
}
elseif (is_a($this->_['.'][$key], get_class())) return false;
else return '';
} else return null;
}
public function echoNode($echo=true) {
ini_set('xdebug.var_display_max_depth', 100);
ini_set('xdebug.var_display_max_children', 256);
ini_set('xdebug.var_display_max_data', 1024);
$node_ob = clone $this;
$recurse = function( &$node ) use (&$recurse)
{
if ( !empty($node->_['.']) )
foreach ($node->_['.'] as $k => $v)
if ( is_a($v, get_class()) ) $recurse($v);
$node->_['..'] = $node->_['..']->_['$'];
$node->_['/'] = $node->_['/']->_['$'];
return $node;
};
$result = $recurse($node_ob);
ob_start(); var_dump($result);
$str = preg_replace('/\s+(=>)\s+/s','=>',ob_get_clean());
$str = str_replace([ "class "],'',$str);
$str = preg_replace(['/protected/', '/#[0-9]+ \([0-9]+\)/', '/\n\s*}/',
'/string\([0-9]+\)\s/','/array\([0-9]+\)\s/', '/object\((Node)\) {/',
'/bool\(([a-zA-Z]+)\)/', '/int\(([0-9]+)\)/','/\n\s*(\s.\..=>)/',],'$1',$str);
$str = preg_replace(['/\n\s*\$_=>\s*/s','/\n\s*(.#.=>)/s','/\n\s*(.\.\..=>)/s',
'/\s+(.\!.=>)/s','/\s+(.\~.=>)/s','/\n\s*(.\/.=>)/s',
'/{/', '/\s*(.\$.=>)/'],' $1',$str); // cut \n
if ($echo) echo $str;
return $str;
}
protected static function _rConfig(&$parent, $key=null) {
# If $key is not provided, all contents of $parent will be configured recursively.
# $key can specify a single key on $parent to recursively configure
$next_ = ['#'=>$parent->_['#']+1,'!'=>$parent->_['!'],'..'=>$parent,'/'=>$parent->_['/']];
foreach ($parent->_['.'] as $k => &$v) {
if ($key===null || $k===$key) {
$next_['$'] = $k;
if ( is_array($v) && $parent->_['~']) {
$next_['~'] = $parent->_['~']===true ? true : false;
$next_['.'] = $v;
$v = new static();
$v->_ = array_merge($v->_, $next_);
if (!empty($v->_['.'])) self::_rConfig($v);
} elseif ( is_a($v, get_class()) ) {
$next_['~'] = $v->_['~'];
# unset from old parent if we need to:
if ($v!==$v->_['..'] && isset($v->_['..']['.'][ $v->_['$'] ])
&& $v->_['..']['.'][ $v->_['$'] ]===$v)
unset($v->_['..']['.'][ $v->_['$'] ]);
$v->_ = array_merge($v->_, $next_);
if (!empty($v->_['.'])) self::_rConfig($v);
}
}
}
}
}
$node = new Node([
'1-leaf' => 'stringvalue',
'1-tree1' =>
[
'2-tree' =>
[
'3-leaf' => 'stringvalue',
'3-tree' =>
[
['4-leaf' => 'stringvalue'],
]
]
],
'1-tree2' => ['2-leaf' => 'stringvalue'],
]);
echo gettype($node['1-tree1']['2-tree']['3-tree'])."\n";
<?php
class NodeBase
{
protected $_node;
public function __construct($array=[], $key_or_arr=null, $convert=null)
{
is_array($key_or_arr) ? extract($key_or_arr) : $key = $key_or_arr;
$this->_node = [
'key' => isset($key) ? $key : 'root',
'depth' => 0,
'convert' => isset($convert) ? $convert : true,
'arrays' => isset($arrays) ? $arrays : [],
'parent'=>$this, 'root'=>$this, 'children'=> $array
];
if ( !empty($this->_node['children']) ) self::_recurseNodes($this);
}
public function addNode ($data, $key_or_arr=null, $convert=null)
{
is_array($key_or_arr) ? extract($key_or_arr) : $key = $key_or_arr;
$n =& $this->_node;
if ( $key!==null &&
array_key_exists($key,$n['children']) ) return false; #overwriteERROR
if (is_array($data) && $convert!==null || $n['convert']===true) {
if($key===null){$key=0;while(array_key_exists($key,$n['children']))$key++;}
$unempty = !empty($data);
$node = new static();
$node->_node = $this->_next_node([
'key'=>$key, 'convert'=>$convert,'children'=>$data
]);
$n['children'][$key] = $node;
if ($unempty) self::_recurseNodes($n['children'][$key]);
} elseif ( is_a($data, get_class()) ) {
if ($key===null) {$key = $data->_node['key']; # try passed node ob's key
if (array_key_exists($key, $n['children'])) return false; #overwriteERROR
}
if ( $n['parent']!==$this ) $this->_unsetFromParent();
$data->_node = $this->_next_node(['key'=>$key,
'convert'=>$convert, 'children'=>$data->_node['children'],]);
// if (in_array($key, $n['arrays']), unset($n['arrays'][$key]));
$n['children'][$key] = $data;
if ( !empty($n['children']) ) self::_recurseNodes($this);
} else {
if($key===null){$key=0;while(array_key_exists($key,$n['children']))$key++;}
// if (is_array($data)) $n['arrays'][] = $key;
$n['children'][$key] = $data; # some other type
}
return $this;
}
public function unsetNode ()
{
}
public function editNode ($parent_or_arr=null, $new_key=null, $convert=null) {
if ( is_array($parent_or_arr) ) extract($parent_or_arr);
else $new_parent=$parent_or_arr;
$n =& $this->_node; $run_recurse = false;
if ($new_parent===null) {
#set key mode:
if ($new_key!==null) {
$arr =& $n['children']; $old_key = $n['key'];
$valid_old = isset($arr[$old_key]) && $arr[$old_key]===$this;
if ( $n['parent']===$this ) $n['key'] = $new_key; #no unset
elseif ( array_key_exists($new_key,$arr) ) { #possible ERROR
$real_key = array_search($this, $arr, true);
if ($real_key!==$old_key) {
if ($valid_old) unset($arr[$real_key]);
else $n['key'] = $real_key;
return false;
}
} else {
$n['children'][$new_key] = $this;
if ($valid_old) unset($n['children'][$old_key]);#must unset
$n['key'] = $new_key;
}
}
}#make root mode:
elseif ($new_parent===$this && $n['parent']!==$this) {
$this->_unsetFromParent();
$n['parent'] = $n['root'] = $this;
if ($new_key!==null) $n['key'] = $new_key;
if ( !empty($n['children']) ) $run_recurse = true;
}#set parent mode:
elseif ($new_parent!==$this && is_a($n['parent'], get_class()) ) {
$n['parent']->addNode($this, $new_key, $convert); #addNode will recurse
}
if ($run_recurse || $convert!==null) self::_recurseNodes($this);
return $this;
}
public function echoNode($echo=true)
{
$node_ob = clone $this;
$recurse = function( &$node ) use (&$recurse)
{
if ( !empty($node->_node['children']) )
foreach ($node->_node['children'] as $k => $v)
if ( is_a($v, get_class()) ) $recurse($v);
$node->_node['parent'] = $node->_node['parent']->_node['key'];
$node->_node['root'] = $node->_node['root']->_node['key'];
return $node;
};
$result = $recurse($node_ob);
ob_start(); var_dump($result);
$str = preg_replace('/(=>)\s+/s','=>',ob_get_clean());
$str = str_replace([ '"','[',']',],'',$str);
$str = preg_replace(['/:protected/', '/#[0-9]+ \([0-9]+\)/', '/\n\s*}/',
'/string\([0-9]+\)\s/','/array\([0-9]+\)\s/', '/object\((Node)\) {/',
'/bool\(([a-zA-Z]+)\)/', '/int\(([0-9]+)\)/','/\n\s*children=>({)/',],'$1',$str);
$str = preg_replace(['/\n\s*(depth=>)/s','/\n\s*(parent=>)/s', '/\n\s*_node=>{()\n\s*/s',
'/\s{5}(convert=>)/s','/\n\s*(root=>)/s','/{/', '/\s*(key=>)/'],' $1',$str);
if ($echo) echo $str;
return $str;
}
protected function _unsetFromParent()
{ # STILL RUNS ON ROOT NODES!
if (isset($this->_node['parent']->_node['children'][$this->_node['key']])
&& $this->_node['parent']->_node['children'][$this->_node['key']]===$this
) { unset($this->_node['parent']->_node['children'][$this->_node['key']]);}
}
protected function _next_node($_node=[])
{ # any keys passed in with value of null will not be used!
return array_merge( [
'key' => null,
'depth' => $this->_node['depth'] + 1,
'convert' => $this->_node['convert'],
'parent' => $this,
'root' => $this->_node['root'],
'children'=> [] ],
array_filter($_node,function($v){return($v)!==null;}));
}
protected static function _recurseNodes(&$parent)
{
$next_node = [
'key' => null, # just so it's at the beginning
'depth' => $parent->_node['depth'] + 1,
'convert'=> $parent->_node['convert'],
'parent' => $parent,
'root' => $parent->_node['root'],];
foreach ($parent->_node['children'] as $k => &$v) {
$next_node['key'] = $k;
if ($parent->_node['convert'] && is_array($v)) {
$next_node['children'] = $v;
$v = new static();
$v->_node = $next_node;
if (!empty($v->_node['children'])) {self::_recurseNodes($v);}
} elseif ( is_a($v, get_class()) ) {
if ($v->_node['parent']!==$v) {
if (isset($v->_node['parent']->_node['children'][$v->_node['key']])
&& $v->_node['parent']->_node['children'][$v->_node['key']]===$v
) { unset($v->_node['parent']->_node['children'][$v->_node['key']]);}
}
$next_node['children'] = $v->_node['children'];
$v->_node = $next_node;
if ( !empty($v->_node['children']) ){self::_recurseNodes($v);}
}
}
}
}
class NodeTree extends NodeBase
implements Serializable, IteratorAggregate, ArrayAccess, Countable
{
# public node obj methods { access $this->_node property } return type
public function parent() { return $this->_node['parent']; } #reference
public function root() { return $this->_node['root']; } #reference
public function parentKey() { return $this->parent()->key(); } #key
public function rootKey() { return $this->root()->key(); } #key
public function getKey() { return $this->nodeKey(); } #key
public function nextIdx() { $i=0;
while(array_key_exists($i,$this->_node['children']))$i++; #integer
return $i; } # returns lowest integer key not in use
public function depth() { return $this->_node['depth']; } #integer
public function isRoot(){return $this->_node['root']===$this;} #boolean
public function getChild($key){
return $this->_node['children'][$key]; } #element
public function getSibling($key){
return $this->_node['parent']->_node['children'][$key]; } #element
public function rootChild($key){
return $this->_node['root']->_node['children'][$key]; } #element
public function hasKey($key) {
return array_key_exists($key, $this->_node['children']); #boolean
}
public function serialize(){
return serialize($this->_node['children']); # object to string
}
public function unserialize($serialized) {
$this->_node['children'] = unserialize($serialized);
}
public function getIterator() {
return new ArrayIterator( $this->_node['children'] );
}
public function count() { return count( $this->_node['children'] ); }
public function length(){ return $this->count(); }
public function offsetSet($key, $value) {
if ($key===null) {
$this->_node['children'][] = $value;
} else {
$this->_node['children'][$key] = $value;
}
}
public function offsetGet($key) {
return array_key_exists( $key,$this->_node['children'] )
? $this->_node['children'][$key] : null;
}
public function offsetExists($key) {
return array_key_exists( $key, $this->_node['children'] );
}
public function offsetUnset($key) {
unset( $this->_node['children'][$key] );
}
}
$node = new NodeTree([
'1-leaf' => 'stringvalue',
'1-tree1' =>
[
'2-tree' =>
[
'3-leaf' => 'stringvalue',
'3-tree' =>
[
['4-leaf' => 'stringvalue'],
]
]
],
'1-tree2' => ['2-leaf' => 'stringvalue'],
]);
$node->addNode(['new'=>'child'], 'newnode');
// $node->nodeKey('ROOT');
$node->echoNode('echo');
$arr1 = new NodeTree([1, 2, 3]);
$arr1["four"] = 4;
foreach ($arr1 as $k => $v) echo "$k=>$v\n";
$arr2 = ["i'm", "an", "array?"];
$arr2 = new NodeTree($arr2);
$arr2[] = 4;
foreach ($arr2 as $k => $v) echo "$k=>$v\n";
# OLD OLD OLD OLD
<?php
class NodeBase
{
protected $_node;
public function __construct($array=[], $_node=[])
{
$this->_node = array_merge([
'key' =>'root', 'depth'=> 0, 'convert' => true,
'parent'=> null, 'root' =>null, 'children'=> $array,
], $_node);
if ( !isset($this->_node['parent']) ) {
$this->_node['parent'] = $this;
$this->_node['root'] = $this;
} elseif ($this->_node['parent']!==$this) {
if (isset($this->_node['parent']->_node['children'][$this->_node['key']])
&& $this->_node['parent']->_node['children'][$this->_node['key']]===$this
) { unset($this->_node['parent']->_node['children'][$this->_node['key']]);}
}
if ( !empty($this->_node['children']) ) self::_recurseNodes($this);
}
public function nodeToString($echo=null)
{
$node_ob = clone $this;
$recurse = function( &$node ) use (&$recurse)
{
if ( !empty($node->_node['children']) )
foreach ($node->_node['children'] as $k => $v)
if ( is_a($v, get_class()) ) $recurse($v);
$node->_node['parent'] = $node->_node['parent']->_node['key'];
$node->_node['root'] = $node->_node['root']->_node['key'];
return $node;
};
$result = $recurse($node_ob);
ob_start(); var_dump($result);
$str = preg_replace('/(=>)\s+/s','=>',ob_get_clean());
$str = str_replace([ '"','[',']',],'',$str);
$str = preg_replace(['/:protected/', '/#[0-9]+ \([0-9]+\)/', '/\n\s*}/',
'/string\([0-9]+\)\s/','/array\([0-9]+\)\s/', '/object\((Node)\) {/',
'/bool\(([a-zA-Z]+)\)/', '/int\(([0-9]+)\)/','/\n\s*children=>({)/',],'$1',$str);
$str = preg_replace(['/\n\s*(depth=>)/s','/\n\s*(parent=>)/s', '/\n\s*_node=>{()\n\s*/s',
'/\s{5}(convert=>)/s','/\n\s*(root=>)/s','/{/', '/\s*(key=>)/'],' $1',$str);
if (!empty($echo)) echo $str;
return $str;
}
public function nodeKey($new_key=null)
{
if ( $new_key===null ){return $this->_node['key'];} # getter mode
$arr =& $this->_node['children']; $old_key = $this->_node['key'];
$valid_old = isset($arr[$old_key]) && $arr[$old_key]===$this;
if ( $this->_node['parent']===$this ) {
$this->_node['key'] = $new_key; return $this; #DONE
} elseif ( array_key_exists($new_key,$arr) ) { #something's wrong
$real_key = array_search($this, $arr, true);
if ($new_key===$real_key && $real_key===$old_key){return $this;}
elseif ($real_key!==$old_key ){
if ($valid_old) {unset($arr[$real_key]);}
else {$this->_node['key'] = $real_key;}
return false;
}
} else {
$this->_node['children'][$new_key] =& $this;
if ($valid_old) unset($this->_node['children'][$old_key]);
$this->_node['key'] = $new_key; return $this;
}
}
public function rmFromParent($new_key=null) {
if ( $this->_node['parent']!==$this ) {
$this->_unsetFromParent();
$this->_node['parent'] = $this->_node['root'] = $this;
if ($new_key!==null) $this->_node['key'] = $new_key;
if ( !empty($this->_node['children']) ) self::_recurseNodes($this);
}
}
public function addToParent($parent, $new_key=null) {
if ($parent!==$this && is_a($parent, get_class()) )
$parent->addChild($this, $new_key);
}
public function addChild ($data, $key=null, $convert=null)
{
$children =& $this->_node['children'];
if ($key!==null && array_key_exists($key,$children) )return false; #overwriteERROR
if (is_array($data) && $convert!==null || $this->_node['convert']===true) {
if($key===null){$key=0;while(array_key_exists($key,$children))$key++;}
$unempty = !empty($data);
$node = new static();
$node->_node = $this->_next_node(['key'=>$key,
'convert'=>$convert, 'children'=>$data]);
$this->_node['children'][$key] = $node;
if ($unempty) self::_recurseNodes($this->_node['children'][$key]);
} elseif ( is_a($data, get_class()) ) {
if ($key===null) {$key = $data->_node['key']; # try passed node ob's key
if (array_key_exists($key, $children)) return false; #overwriteERROR
}
if ( $this->_node['parent']!==$this ) $this->_unsetFromParent();
$data->_node = $this->_next_node(['key'=>$key,
'convert'=>$convert, 'children'=>$data->_node['children'],]);
$children[$key] = $data;
if ( !empty($this->_node['children']) ) self::_recurseNodes($this);
} else {
if($key===null){$key=0;while(array_key_exists($key,$children))$key++;}
$children[$key] = $data; # some other type
}
return $this;
}
protected static function _recurseNodes(&$parent)
{
$next_node = [
'key' => null, # just so it's at the beginning
'depth' => $parent->_node['depth'] + 1,
'convert'=> $parent->_node['convert'],
'parent' => $parent,
'root' => $parent->_node['root'],];
foreach ($parent->_node['children'] as $k => &$v) {
$next_node['key'] = $k;
if ($parent->_node['convert'] && is_array($v)) {
$next_node['children'] = $v;
$v = new static();
$v->_node = $next_node;
if (!empty($v->_node['children'])) {self::_recurseNodes($v);}
} elseif ( is_a($v, get_class()) ) {
if ($v->_node['parent']!==$v) {
if (isset($v->_node['parent']->_node['children'][$v->_node['key']])
&& $v->_node['parent']->_node['children'][$v->_node['key']]===$v
) { unset($v->_node['parent']->_node['children'][$v->_node['key']]);}
}
$next_node['children'] = $v->_node['children'];
$v->_node = $next_node;
if ( !empty($v->_node['children']) ){self::_recurseNodes($v);}
}
}
}
protected function _unsetFromParent() { # STILL RUNS ON ROOT NODES!
if (isset($this->_node['parent']->_node['children'][$this->_node['key']])
&& $this->_node['parent']->_node['children'][$this->_node['key']]===$this
) { unset($this->_node['parent']->_node['children'][$this->_node['key']]);}
}
protected function _next_node($_node=[])
{ # any keys passed in with value of null will not be used!
return array_merge( [
'key' => null,
'depth' => $this->_node['depth'] + 1,
'convert' => $this->_node['convert'],
'parent' => $this,
'root' => $this->_node['root'],
'children'=> [] ],
array_filter($_node,function($v){return($v)!==null;}));
}
}
class NodeTree extends NodeBase
implements Serializable, IteratorAggregate, ArrayAccess, Countable
{
# public node obj methods { access $this->_node property } return type
public function parent() { return $this->_node['parent']; } #reference
public function root() { return $this->_node['root']; } #reference
public function parentKey() { return $this->parent()->key(); } #key
public function rootKey() { return $this->root()->key(); } #key
public function getKey() { return $this->nodeKey(); } #key
public function setKey($key){ return $this->nodeKey($key);} #this or false
public function nextIdx() { $i=0;
while(array_key_exists($i,$this->_node['children']))$i++; #integer
return $i; } # returns lowest integer key not in use
public function depth() { return $this->_node['depth']; } #integer
public function isRoot(){return $this->_node['root']===$this;} #boolean
public function getChild($key){
return $this->_node['children'][$key]; } #element
public function getSibling($key){
return $this->_node['parent']->_node['children'][$key]; } #element
public function rootChild($key){
return $this->_node['root']->_node['children'][$key]; } #element
public function hasKey($key) {
return array_key_exists($key, $this->_node['children']); #boolean
}
public function serialize(){
return serialize($this->_node['children']); # object to string
}
public function unserialize($serialized) {
$this->_node['children'] = unserialize($serialized);
}
public function getIterator() {
return new ArrayIterator( $this->_node['children'] );
}
public function count() { return count( $this->_node['children'] ); }
public function length(){ return $this->count(); }
public function offsetSet($key, $value) {
if ($key===null) {
$this->_node['children'][] = $value;
} else {
$this->_node['children'][$key] = $value;
}
}
public function offsetGet($key) {
return array_key_exists( $key,$this->_node['children'] )
? $this->_node['children'][$key] : null;
}
public function offsetExists($key) {
return array_key_exists( $key, $this->_node['children'] );
}
public function offsetUnset($key) {
unset( $this->_node['children'][$key] );
}
}
$node = new NodeTree([
'1-leaf' => 'stringvalue',
'1-tree1' =>
[
'2-tree' =>
[
'3-leaf' => 'stringvalue',
'3-tree' =>
[
['4-leaf' => 'stringvalue'],
]
]
],
'1-tree2' => ['2-leaf' => 'stringvalue'],
]);
// var_dump($node);
$node->addChild(['new'=>'child'], 'newnode');
$node->nodeKey('ROOT');
$node->nodeToString('echo');
$arr1 = new NodeTree([1, 2, 3]);
$arr1["four"] = 4;
foreach ($arr1 as $k => $v) echo "$k=>$v\n";
$arr2 = ["i'm", "an", "array?"];
$arr2 = new NodeTree($arr2);
$arr2[] = 4;
foreach ($arr2 as $k => $v) echo "$k=>$v\n";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment