R.php

<?php

function R(...$args){
    // echo 'r func';exit;
    static $theObject = null;
    $theObject = $theObject ?? new R();
    // $theObject = new R();
    // echo 'za za';
    // var_dump($theObject);
    // exit;
    return $theObject(...$args);
};

class R {

    protected $data = [];
    protected $errorHandler = null;
    protected $fileHandlers = [
        // '.json'=>'json_decode'
    ];

    static public function setup(){
        return R();
    }

    public function __construct(){
        $json_decoder = function($content,$ext){
            return json_decode($content,true);
        };
        $this->setFileHandler($json_decoder,'json');
        // exit
        // $this->errorHandler = [$this,'handleError'];
        // $this->setErrorHandler([$this,'handleError']);
        // $this->fileHandlers['.json'] => function($content,$file)
    }

    // protected function handleError($errorMessage){
    //     trigger_error($errorMessage);
    // }
    public function setFileHandler($callable,$ext){
        $this->fileHandlers[$ext] = $callable;
    }
    public function set($key,$value){
        $key = strtolower($key);
        $this->data[$key] = $value;
        if (is_array($value)){
            var_dump($value);
            throw new \Exception("value is an array");
        }
        // echo 'set key'.$key."\n";
    }
    public function loadDir($dirPath,$prefix='',$prefixWithFileNames=FALSE,$putSubArrays=TRUE,$recurse=TRUE){
        if (!is_dir($dirPath))throw new \Exception("A dir is NOT found @ '{$dirPath}'");
        $dh = opendir($dirPath);
        while ($file==readdir($dh)){
            if ($file=='.'||$file='..')continue;
            $prefix = $prefix.($prefixWithFileNames ? pathinfo($file,PATHINFO_FILENAME).'.' : '');
            $path = $dir.'/'.$file;
            if ($recurse&&is_dir($path))$this->loadDir($path,$prefix,$prefixWithFileNames,$putSubArrays);
            else if (is_file($path))$this->load($path,$prefix,$putSubArrays);
        }
        
    }
    /** Loads an array from the given file, using a pre-set file handler, based upon the extension */
    public function load($filePath,$prefix='',$putSubArrays=TRUE){
        if (!file_exists($filePath))throw new \Exception("A file does not exist @ '{$filePath}'");
        
        $ext = pathinfo($filePath,PATHINFO_EXTENSION);
        $fileHandler = $this->fileHandlers[$ext] ?? null;
        if ($fileHandler===null)throw new \Exception("A file handler does not exist for extension '{$ext}'");
        $data = $fileHandler(file_get_contents($filePath),$ext);
        // var_dump($data);
        // exit;
        $this->put($data,$prefix,$putSubArrays);
        // var_dump($this->data);
        // exit;
    }
    /** Prefix will be pre-pended to every single key of the array. If $putSubArrays is true, then `put` will be called recursively for every array-value
     * 
     */
    public function put($array,$prefix='', $putSubArrays=FALSE){
        foreach ($array as $key=>$value){
            if (is_array($value)&&$putSubArrays)$this->put($value,$prefix.$key.'.',$putSubArrays);
            else $this->set($prefix.$key,$value);
        }
    }
    public function get($key,$defaultValue=NULL){
        $key = strtolower($key);
        $args = func_get_args();
        $argCount = count($args);
        if (substr($key,-1)=='.'){
            $entries = [];
            foreach ($this->data as $entryKey=>$value){
                if (substr($key,0,-1)==$entryKey){
                    $entries['='] = $value;
                }else if (substr($entryKey,0,strlen($key))==substr($key,0)){
                    $entries[substr($entryKey,strlen($key))] = $value;
                }
            }
            if (count($entries)>0)return $entries;
            if ($argCount==2)return $defaultValue;

            throw new \Exception("No values set @ '{$key}'");
        }
        if (isset($this->data[$key]))return $this->data[$key];
        else if ($argCount==2)return $defaultValue;
        
        throw new \Exception("No value set @ '{$key}'. If you're looking for an array, put a period (.) at the end of the key request.");
    }

    /** 1) No args: return the instance
     *  2) One arg ending with [a-zA-Z]: Return the stored value or throw an exception
     *  3) One arg ending with \.: Return an array of values at that arg. Throw an exception if there are no values
     *      - For R(key.), return ['='=>(value @ key), 'child'=>(value @ key.child)]
     *  4) Two args: function as 2) or 3) if a value is set, else return the second arg (instead of throwing an exception)
     */
     public function __invoke($key=NULL, $default=NULL){
        // var_dump(func_get_args());exit;
        $args = func_get_args();
        // var_dump($args);
        if (count($args)===0)return $this;
        $arg1 = $args[0];

        return $this->get(...$args);
    }
}

// $className = "R";

// R("cats");