21 Дек. 2020 в 22:38

Настройки для PHP-скриптов

img

<?php
/**
 *    unicode без BOM / (0xef, 0xbb, 0xbf) / chr(239), chr(187), chr(191)
 *
 * @version 2.7.20
 * @todo Оболочка для конфигурационных массивов
 * @example $object = new Config( ['param' => [ 'var' => 1 ] ] );
 * @example echo $object->param->var;
 *
 * @uses ArrayAccess
 * @uses ArrayIterator
 * @uses array_unshift
 * @uses array_keys
 * @uses array_values
 * @uses array_reverse
 * @uses array_flip
 * @uses array_search
 * @uses array_unique
 * @uses in_array
 * @uses function_exists
 * @uses call_user_func
 * @uses serialize
 * @uses implode
 *
 * @magic __construct
 * @magic __call
 * @magic __toString
 * @magic __isset
 * @magic __unset
 * @magic __get
 * @magic __set
 *************************************************************************************************/
final class Config implements ArrayAccess {

    
/**
     * @access protected
     * @const  array
     */
    
protected const _EMPTY_VALUES =
    [
        
NULLFALSE'    '''' '' ', [], ['    '], [''], [' '], [' ']
    ];

    
/**
     * @access protected
     * @const  array
     */
    
protected const _NO_CHANGE_KEYS =
    [
        
'connection',
        
'password',
        
'token'
    
];


    
/**
     * @access protected
     * @var    integer
     */
    
protected static int $_count = -1;


    
/**
     * @access protected
     * @var    integer
     */
    
protected static float $_time 0;


    
/**
     *    Singleton
     *
     * @final
     * @static
     * @access public
     * @param  array $array
     * @return object singleton
     */
    
final public static function instance(array $array = []): self
    
{
        
/**
         * @staticvar object singleton
         */
        
static $_;

        if ( ! 
$_)
        {
           if (
_DEBUG)
           {
              static::
$_time microtime(TRUE);
           }

           
$_ = new static($array);
        }

        return 
$_;
    }


    
/**
     *    Singleton
     *
     * @final
     * @static
     * @access public
     * @param  array $array
     * @return object singleton
     */
    
final public static function factory(array $array = []) /** singleton **/
    
{
        return static::
instance($array);
    }


    
/**
     * @access private
     * @var    array
     */
    
private array $_ = [];

    
/**
     * @access private
     * @var    array
     */
    
private array $_keys = [];


    
/**
     *    __construct
     *
     * @final
     * @access public
     * @param  array|object Config $input
     * @param  array $keys_object
     * @return no type
     */
    
final public function __construct($input = [], array $keys_object = []) /** no type **/
    
{
        static::
$_count++;

        if (
$input instanceof self)
           
$this->_in_object($input$keys_object);
        else
           
$this->_to_object
($input);
    }


    
/**
     *    __clone
     *
     * @final
     * @access private
     */
    
final private function __clone() { }


    
/**
     *    __call
     *
     *    $keys    = $object->array->name->keys(); or if ($object->name->keys('str')) { ... }
     *    $flip    = $object->array->name->flip();
     *    $values  = $object->array->name->values(); or if ($object->name->values('str')) { ... }
     *    $reverse = $object->array->name->reverse()->as_array();
     *    $array   = $object->array->names->values()->flip('array');
     *
     * @final
     * @access public
     * @return mixed
     */
    
final public function __call($method$args/** mixed **/
    
{
        if (
in_array($method, ['keys''values''reverse''flip']) && function_exists('array_' .$method))
        {
           
$array call_user_func('array_' .$method$this->as_array());

           if (isset(
$args[0]))
           {
              if (
$args[0] === 'array')
                 return 
$array;
              elseif (
$method === 'keys' || $method === 'values')
              {
                 return 
in_array($args[0], $array);
              }
           }

           return new 
self($array);
        }
    }


    
/**
     *    __toString
     *
     *    echo $object;
     *
     * @access public
     * @return string
     */
    
public function __toString(): string
    
{
        return 
serialize($this->_);
    }


    
/**
     *    foreach ($object->getIterator() as $key => $value) { ... }
     *
     * @access public
     * @return Traversable
     */
    
public function getIterator(): Traversable
    
{
        return new 
ArrayIterator($this->_);
    }


    
/**
     *    $array = $object->getArrayCopy();
     *
     * @access public
     * @return iterable
     */
    
public function getArrayCopy(): iterable
    
{
        return (array) 
$this->_;
    }


    
/**
     *    __isset
     *
     *    if (isset($object->key)) { ... }
     *
     * @access public
     * @param  string $key
     * @return boolean
     */
    
public function __isset($key): bool
    
{
        return isset(
$this->_[$key]);
    }


    
/**
     *    __unset
     *
     *    unset($object->key);
     *
     * @access public
     * @param  string $key
     * @return void
     */
    
public function __unset($key NULL): void
    
{
        if (
$key === NULL)
           
$this->_unset();
        else
        {
           unset(
$this->_[$key]);
           if ((
$key array_search($key$this->_keys)) !== FALSE)
           {
              unset(
$this->_keys[$key]); // unset key
           
}
        }
    }


    
/**
     *    __set
     *
     *    $object->key1->key2->key3-> ... = 'set value';
     *
     * @access public
     * @param  string $key
     * @param  mixed  $value
     * @return void
     */
    
public function __set($key NULL$value NULL): void
    
{
        if (isset(
$this->_[$key]) && in_array($keyself::_NO_CHANGE_KEYS))
        { 
/** return void; **/ }
        else
        {
           if (
$key === NULL)
              
$this->_[] = $value;
           else
           {
              
$this->_[$key] = $value;
           }

           
$this->_to_object($this->_);
        }
    }


    
/**
     *    __get
     *
     *    $object->key1->key2->key3-> ...
     *
     * @access public
     * @param  string $key
     * @return mixed
     */
    
public function & __get($key/** mixed **/
    
{
        if ((
$_ = ($this->_[$key] ?? NULL)) instanceof self)
        {
           
$_ = ( ! in_array($key$this->_keys) && in_array($_->as_array(), self::_EMPTY_VALUESTRUE)
            ? 
$_->result($key)
            : 
$_);
        }

        return 
$_;
    }


    
/**
     *    [!] ArrayAccess
     *    @link https://www.php.net/manual/en/class.arrayaccess.php
     *
     * @access public
     * @param  string $key
     * @return boolean
     */
    
public function offsetExists($key): bool
    
{
        return 
$this->__isset($key);
    }


    
/**
     *    [!] ArrayAccess
     *    @link https://www.php.net/manual/en/class.arrayaccess.php
     *
     * @access public
     * @param  string $key
     * @return void
     */
    
public function offsetUnset($key): void
    
{
        
$this->__unset($key);
    }


    
/**
     *    [!] ArrayAccess
     *    @link https://www.php.net/manual/en/class.arrayaccess.php
     *
     * @access public
     * @param  string $key
     * @param  mixed  $value
     * @return void
     */
    
public function offsetSet($key NULL$value NULL): void
    
{
        
$this->__set($key$value);
    }


    
/**
     *    [!] ArrayAccess
     *    @link https://www.php.net/manual/en/class.arrayaccess.php
     *
     * @access public
     * @param  string $key
     * @return mixed
     */
    
public function & offsetGet($key/** mixed **/
    
{
        return 
$this->__get($key);
    }


    
/**
     *    DEBUG COUNT
     *
     * @final
     * @access public
     * @return integer
     */
    
final public function count(): int
    
{
        return static::
$_count;
    }


    
/**
     *    DEBUG TIME
     *
     * @final
     * @access public
     * @return integer
     */
    
final public function time(): float
    
{
        return static::
$_time;
    }


    
/**
     *    $object->key->empty();
     *    $object->key->empty('keyname');
     *
     * @access public
     * @return mixed
     */
    
public function empty($key NULL$unset FALSE/** mixed **/
    
{
        
$result $this->result($key$unset);
        if (
$result instanceof self)
        {
           
$result $result->getArrayCopy();
        }

        return (empty(
$result) ? NULL $result);
    }


    
/**
     *    $object->key->result('key', TRUE); - unset($object->key) and return value;
     *    $object->key->result('key'); or $object->key->result();
     *
     * @access public
     * @param  string  $key
     * @param  boolean $unset
     * @return mixed
     */
    
public function & result($key NULL$unset FALSE/** mixed **/
    
{
        if (empty(
$key))
        {
           
$result = new self($this->_);
           ! 
$unset || $this->__unset();
        }
        elseif ((
$result $this->__get($key)) && $unset)
        {
           
$this->__unset($key);
        }

        return 
$result;
    }


    
/**
     *    $object->key->last();
     *
     * @access public
     * @return mixed
     */
    
public function & last() /** mixed **/
    
{
        return 
$this->__get(key(array_slice($this->_, -1)));
    }


    
/**
     *    echo $object->key->implode(',');
     *
     * @access public
     * @param  string $delimiter
     * @return string
     */
    
public function implode(string $delimiter '|'): string
    
{
        return 
implode($delimiter$this->_);
    }


    
/**
     *    $object->key->unshift(['key' => 'value']);
     *
     * @access public
     * @param  mixed $mixed
     * @return self
     */
    
public function unshift($mixed): self
    
{
        
$array $this->as_array();
        
array_unshift($array$mixed);
        
$this->_to_object(array_unique($array));
        return 
$this;
    }


    
/**
     *    $object->array->map('trim');
     *    $object->array->map(function($_){ return TRUE;})->as_array();
     *
     * @access public
     * @param  mixed $callbacks
     * @param  iterable $iterable
     * @return self
     */
    
public function map($callbacksiterable $iterable NULL): self
    
{
        if (
$iterable === NULL)
        {
           
$iterable $this->_;
        }

        foreach (
$iterable as $key => $_)
        {
            
$iterable[$key] =
            (
                
is_iterable($_)
                    ? 
$this->map($callbacks$iterable[$key])
                    : 
call_user_func($callbacks$iterable[$key])
            );
        }

        return new 
self($iterable);
    }


    
/**
     *    $array1 <<<-- $array2
     *
     *    $object->key->merge(['key' => 'value']);
     *
     *    $object->key->key2 = ['keyname' => TRUE];
     *    $object->key->merge('key2');
     *    return $object->key->keyname .... a key2 unsete
     *
     * @access public
     * @param  array|string  $input
     * @return self
     */
    
public function merge($input = []): self
    
{
        if (
is_string($input) && isset($this->_[$input]) && ($this->_[$input] instanceof self))
        {
           
$key $input;
           
$input $this->_[$input]->as_array();
           unset(
$this->_[$key]);
        }

        
$this->_to_object
        
(
            
$this->_merge
            
(
                (
$this->instanceof self)
                    ? 
$this->_->as_array()
                    : 
$this->_,
                
$input instanceof self
                    
$input->as_array()
                    : (array) 
$input
            
)
        );

        return 
$this;
    }


    
/**
     *    $array1 -->>> $array2
     *
     *    $object->key->merge_revers(['key' => 'value']);
     *
     * @access public
     * @param  array  $array
     * @return self
     */
    
public function merge_revers(array $array = []): self
    
{
        
$this->_to_object
        
(
            
$this->_merge
            
(
                
$array,
                (
$this->instanceof self)
                    ? 
$this->_->as_array()
                    : 
$this->_
            
)
        );

        return 
$this;
    }


    
/**
     *    $object->key->load(['/path/config/array.php', '/path/array.php']);
     *    $object->key2->load('/path/config/array2.php');
     *
     * @access public
     * @param  array|string  $paths
     * @return self
     */
    
public function load($paths NULL): self
    
{
        if ( ! empty(
$paths))
        {
           
$array $this->as_array();
           foreach ((array) 
$paths as $_)
           {
               
$array $this->_merge($array, (array) require $_);
           }

           
$this->_to_object($array);
        }

        return 
$this;
    }


    
/**
     *    $object->key->load_revers(['/path/config/array.php', '/path/array.php']);
     *    $object->key->load_revers('/path/config/array.php');
     *
     * @access public
     * @param  array|string  $paths
     * @return self
     */
    
public function load_revers($paths NULL): self
    
{
        if ( ! empty(
$paths))
        {
           
$array $this->as_array();
           foreach ((array) 
$paths as $_)
           {
               
$array $this->_merge((array) require $_$array);
           }

           
$this->_to_object($array);
        }

        return 
$this;
    }


    
/**
     *    $object->as_array()
     *    $object->key->as_array()
     *    $object->key->as_array(TRUE) or $object->key->as_array('UNSET')
     *
     * @final
     * @access public
     * @param  boolean $unset
     * @return array
     */
    
final public function & as_array($unset FALSE): array
    {
        
$array = [];
        foreach (
$this->as $key => $_)
        {
           
$array[$key] = ($_ instanceof self)
               ? 
$_->as_array()
               : 
$_;
        }

        ! 
$unset || $this->__unset();

        return 
$array;
    }


    
/**
     *    $object->as_keys()
     *    $object->key->as_keys()
     *
     * @final
     * @access public
     * @return array
     */
    
final public function as_keys(): array
    {
        return 
$this->_keys;
    }


    
/**
     *    if ($object->key->is_key('keyname')) { ... }
     *
     * @final
     * @access public
     * @param  string $key
     * @return boolean
     */
    
final public function is_key(string $key NULL): bool
    
{
        return 
in_array($key$this->_keys);
    }


    
/**
     *    $object->default('keyname', 'typename', ['keydefault' => 'value']);
     *    $object->keyname->as_array();
     *
     * @final
     * @access public
     * @param  string $key
     * @param  string $type
     * @param  array  $default
     * @return self
     */
    
final public function default($key NULL$type NULL, array $default = []): self
    
{
        if ( ! isset(
$this->_[$key]))
        {
           
$this->_[$key] = new self;
        }

        
$this->_[$key] = new self
        
(
            (
$type && $this->_[$key]->{$type})
                ? 
$this->_merge($default$this->_[$key]->{$type}->as_array())
                : 
$default
        
);

        return 
$this;
    }


    
/**
     *    $array1 <<<-- $array2
     *
     * @final
     * @access protected
     * @param  array $array1
     * @param  array $array2
     * @return array
     */
    
final protected function _merge(array $array1, array $array2): array
    {
        if (
array_keys(($_ array_keys($array2))) !== $_// is_assoc
        
{
           foreach (
$array2 as $key => $_)
               
$array1[$key] = (is_array($_) && isset($array1[$key]) && is_array($array1[$key]))
                               ? 
$this->_merge($array1[$key], $_)
                               : 
$_;
        }
        else
        {
            foreach (
$array2 as $_)
            {
                if ( ! 
in_array($_$array1TRUE))
                   
$array1[] = $_;
            }
        }
        return 
$array1;
    }


    
/**
     * @final
     * @access protected
     * @param  iterable $iterable
     * @return void
     */
    
final protected function _to_object(iterable $iterable): void
    
{
        foreach (
$iterable as $key => $_)
        {
            
$this->_[$key] = (is_array($_)
                ? new 
self($_)
                : 
$_);

            if ( ! 
in_array($key$this->_keys))
            {
               
$this->_keys[] = $key// save keys
            
}
        }
    }


    
/**
     * @final
     * @access protected
     * @param  object Config $input
     * @param  array $keys_object
     * @return void
     */
    
final protected function _in_object(Config $input, array $keys_object): void
    
{
        
$input $input->as_array();
        foreach (
$input as $key => $_)
        {
            
$this->_[$key] = ( ! in_array($key$keys_object)
                                 ? 
$_
                                 
: (is_array($_)
                                     ? new 
self($_)
                                     : 
$_));
        }
    }


    
/**
     * @final
     * @access protected
     * @return void
     */
    
final protected function _unset(): void
    
{
        
$this->_     =
        
$this->_keys = [];
    }
}



// End