fruffl icon

merge protected

fruffl | 01/19/13 04:18:28 AM UTC | 0 ⭐ | 246 👁️ | Never ⏰ | []
PHP |

6.39 KB

|

None

|

0 👍

/

0 👎

<?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