<?PHP
CLASS A EXTENDS FU
{
protected static $__autoConfig =
[
'baz' => 'merge', 'bob', 'foo'
];
protected static $__defaultConfig =
[
'baz' => 1,
'bob' => 10,
'foo' => 100,
];
}
CLASS B EXTENDS A
{
protected static $__autoConfig =
[
'baz', 'bob' => 'merge', 'bar'
];
protected static $__defaultConfig =
[
'baz' => 5,
'bob' => 50,
'bar' => 5000,
];
}
/*
A::baz => merge
A::bob
A::foo
B : A
B::baz
B::bob => merge
B::bar
expected:
B::baz
B::bob => merge
B::foo
B::bar
*/
$fu = new B;
var_dump($fu);
return;
/*
object(root\B)#6 (2) {
["__initConfig":protected]=>
array(5) {
["__run"]=>
bool(true)
["baz"]=>
int(5)
["bob"]=>
int(50)
["foo"]=>
int(100)
["bar"]=>
int(5000)
}
["debug"]=>
&array(2) {
["__autoConfig"]=>
array(4) {
[0]=>
string(3) "baz"
["bob"]=>
string(5) "merge"
[1]=>
string(3) "bar"
[2]=>
string(3) "foo"
}
["__defaultConfig"]=>
array(4) {
["baz"]=>
int(5)
["bob"]=>
int(50)
["foo"]=>
int(100)
["bar"]=>
int(5000)
}
}
}
*/
class fu
{
/**
* @late-state
*/
protected static $__defaultConfig = [];
/**
* @late-state
*/
protected static $__autoConfig = [];
/**
* @read-only
*/
protected $__initConfig = [];
/**
* @cache
*/
private static $__configCache = [];
/**
* @cache
*/
private static $__parentClassCache = [];
/**
* @template
*/
private static $__baseConfig =
[
'__run' => TRUE
];
final public function __construct(array $__options = [])
{
$this->collect()->__initConfig = $this->extend
(
TRUE,
self::$__baseConfig,
self::$__configCache[get_called_class()]['__defaultConfig'],
$__options
);
$this->debug =& self::$__configCache[get_called_class()];
return TRUE === $this->__initConfig['__run']
? $this->__run()
: $this;
}
protected function __run()
{
}
public static function parents($__className = NULL)
{
$parentClasses = &self::$__parentClassCache;
$class = NULL === $__className ? get_called_class() : $__className;
if(isset($parentClasses[$class]))
return $parentClasses[$class];
$classes = [];
do
{
$classes[] = $class;
}
while($class = get_parent_class($class));
$parentClasses[$class] = $classes;
return $classes;
}
/**
*
*
* replace:
* $c->extend(['myNewBar' => ['foo' => 'blop']]);
* $c->extend(['myNewBar' => ['fob' => 'baz']]);
*
* ["myNewBar"]=>
* array(1) {
* ["fob"]=>
* string(3) "baz"
* }
*
*
* extend:
* $c->extend(['myNewBar' => ['foo' => 'blop']]);
* $c->extend(true, ['myNewBar' => ['fob' => 'baz']]);
*
* ["myNewBar"]=>
* array(2) {
* ["foo"]=>
* string(4) "blop"
* ["fob"]=>
* string(3) "baz"
* }
*
* extend multi:
* $c->extend(['myNewBar' => ['foo' => 'blop']]);
* $c->extend(true, $c, ['myNewBar' => ['fob' => 'baz']], ['myNewBar' => ['bla' => 'baz']]);
*
* ["myNewBar"]=>
* array(3) {
* ["foo"]=>
* string(4) "blop"
* ["fob"]=>
* string(3) "baz"
* ["bla"]=>
* string(3) "baz"
* }
*
* @callable array $__data
* @callable array $__target, array $__data
* @callable bool $__recursive, array $__data
* @callable bool $__recursive, array $__target, array $__data
* @param mixed
* @return array|this
* @note $tar is not a referenced array
*/
public function extend()
{
$args = func_get_args();
$tar = $args[0];
$i = 1;
$length = count($args);
$rec = false;
if($tar === true || $tar === false)
{
$rec = $tar;
$tar = isset($args[1]) ? $args[1] : [];
$i = 2;
}
if(!is_array($tar) && !is_object($tar))
$tar = [];
if($length === $i)
{
$tar = $this;
--$i;
}
for( ; $i < $length; $i++)
{
if(NULL === ($opt = $args[$i]))
continue;
foreach($opt as $key => $value)
{
switch(TRUE):
case is_array($tar):
$tar[$key] = (TRUE === $rec && is_array($value) && isset($tar[$key]) && is_array($tar[$key]))
? $this->extend($rec, $tar[$key], $value)
: $value;
break;
case is_object($tar):
$tar->$key = (TRUE === $rec && is_array($value) && isset($tar->$key) && is_array($tar->$key))
? $this->extend($rec, $tar->$key, $value)
: $value;
break;
case is_string($tar):
$tar::${$key} = (TRUE === $rec && is_array($value) && is_array($tar::${$key}))
? $this->extend($rec, $tar::${$key}, $value)
: $value;
break;
endswitch;
}
}
return $tar;
}
private function __collect()
{
$class = get_called_class();
if(isset(self::$__configCache[$class]))
return $this;
self::$__configCache[$class] = [];
// merge + cache __autoConfig, __defaultConfig from childClass up to baseClass
// __autoConfig: array_unique(array_merge())
// __defaultConfig: childClass extends recursively parentClass
$cache = &self::$__configCache[$class];
foreach($this->parents($class) as $lookup)
{
foreach(['__autoConfig', '__defaultConfig'] as $property)
{
if(!isset($lookup::${$property}))
continue;
$value = $lookup::${$property};
if(!isset($cache[$property]))
$cache[$property] = [];
switch($property):
case '__autoConfig':
foreach($value as $key => $flag)
{
$search = is_string($key) ? $key : $flag;
if(isset($cache[$property][$search]))
continue;
$cache[$property][$search] = is_string($key) ? $flag : '';
}
break;
case '__defaultConfig':
if(is_array($cache[$property]) && is_array($value))
$cache[$property] = $this->extend(TRUE, $value, $cache[$property]);
break;
endswitch;
}
}
return $this;
}
}
Comments