PHPDaemon\Config\Parser::__construct PHP Method

__construct() protected method

Constructor
protected __construct ( $file, $target, $included = false ) : void
return void
    protected function __construct($file, $target, $included = false)
    {
        $this->file = $file;
        $this->target = $target;
        $this->revision = ++Object::$lastRevision;
        $this->data = file_get_contents($file);
        if (substr($this->data, 0, 2) === '#!') {
            if (!is_executable($file)) {
                $this->raiseError('Shebang (#!) detected in the first line, but file hasn\'t +x mode.');
                return;
            }
            $this->data = shell_exec($file);
        }
        $this->data = str_replace("\r", '', $this->data);
        $this->length = mb_orig_strlen($this->data);
        $this->state[] = [static::T_ALL, $this->target];
        $this->tokens = [static::T_COMMENT => function ($c) {
            if ($c === "\n") {
                array_pop($this->state);
            }
        }, static::T_STRING_DOUBLE => function ($q) {
            $str = '';
            ++$this->p;
            for (; $this->p < $this->length; ++$this->p) {
                $c = $this->getCurrentChar();
                if ($c === $q) {
                    ++$this->p;
                    break;
                } elseif ($c === '\\') {
                    next:
                    $n = $this->getNextChar();
                    if ($n === $q) {
                        $str .= $q;
                        ++$this->p;
                    } elseif (ctype_digit($n)) {
                        $def = $n;
                        ++$this->p;
                        for (; $this->p < min($this->length, $this->p + 2); ++$this->p) {
                            $n = $this->getNextChar();
                            if (!ctype_digit($n)) {
                                break;
                            }
                            $def .= $n;
                        }
                        $str .= chr((int) $def);
                    } elseif ($n === 'x' || $n === 'X') {
                        $def = $n;
                        ++$this->p;
                        for (; $this->p < min($this->length, $this->p + 2); ++$this->p) {
                            $n = $this->getNextChar();
                            if (!ctype_xdigit($n)) {
                                break;
                            }
                            $def .= $n;
                        }
                        $str .= chr((int) hexdec($def));
                    } else {
                        $str .= $c;
                    }
                } else {
                    $str .= $c;
                }
            }
            if ($this->p >= $this->length) {
                $this->raiseError('Unexpected End-Of-File.');
            }
            return $str;
        }, static::T_STRING => function ($q) {
            $str = '';
            ++$this->p;
            for (; $this->p < $this->length; ++$this->p) {
                $c = $this->getCurrentChar();
                if ($c === $q) {
                    ++$this->p;
                    break;
                } elseif ($c === '\\') {
                    if ($this->getNextChar() === $q) {
                        $str .= $q;
                        ++$this->p;
                    } else {
                        $str .= $c;
                    }
                } else {
                    $str .= $c;
                }
            }
            if ($this->p >= $this->length) {
                $this->raiseError('Unexpected End-Of-File.');
            }
            return $str;
        }, static::T_ALL => function ($c) {
            if (ctype_space($c)) {
            } elseif ($c === '#') {
                $this->state[] = [static::T_COMMENT];
            } elseif ($c === '}') {
                if (sizeof($this->state) > 1) {
                    $this->purgeScope($this->getCurrentScope());
                    array_pop($this->state);
                } else {
                    $this->raiseError('Unexpected \'}\'');
                }
            } elseif (ctype_alnum($c) || $c === '\\') {
                $elements = [''];
                $elTypes = [null];
                $i = 0;
                $tokenType = 0;
                $newLineDetected = null;
                for (; $this->p < $this->length; ++$this->p) {
                    $prePoint = [$this->line, $this->col - 1];
                    $c = $this->getCurrentChar();
                    if (ctype_space($c) || $c === '=' || $c === ',') {
                        if ($c === "\n") {
                            $newLineDetected = $prePoint;
                        }
                        if ($elTypes[$i] !== null) {
                            ++$i;
                            $elTypes[$i] = null;
                        }
                    } elseif ($c === '\'') {
                        if ($elTypes[$i] !== null) {
                            $this->raiseError('Unexpected T_STRING.');
                        }
                        $string = $this->token(static::T_STRING, $c);
                        --$this->p;
                        if ($elTypes[$i] === null) {
                            $elements[$i] = $string;
                            $elTypes[$i] = static::T_STRING;
                        }
                    } elseif ($c === '"') {
                        if ($elTypes[$i] !== null) {
                            $this->raiseError('Unexpected T_STRING_DOUBLE.');
                        }
                        $string = $this->token(static::T_STRING_DOUBLE, $c);
                        --$this->p;
                        if ($elTypes[$i] === null) {
                            $elements[$i] = $string;
                            $elTypes[$i] = static::T_STRING_DOUBLE;
                        }
                    } elseif ($c === '}') {
                        $this->raiseError('Unexpected \'}\' instead of \';\' or \'{\'');
                    } elseif ($c === ';') {
                        if ($newLineDetected) {
                            $this->raiseError('Unexpected new-line instead of \';\'', 'notice', $newLineDetected[0], $newLineDetected[1]);
                        }
                        $tokenType = static::T_VAR;
                        break;
                    } elseif ($c === '{') {
                        $tokenType = static::T_BLOCK;
                        break;
                    } else {
                        if ($elTypes[$i] === static::T_STRING) {
                            $this->raiseError('Unexpected T_CVALUE.');
                        } else {
                            if (!isset($elements[$i])) {
                                $elements[$i] = '';
                            }
                            $elements[$i] .= $c;
                            $elTypes[$i] = static::T_CVALUE;
                        }
                    }
                }
                foreach ($elTypes as $k => $v) {
                    if (static::T_CVALUE === $v) {
                        if (ctype_digit($elements[$k])) {
                            $elements[$k] = (int) $elements[$k];
                        } elseif (is_numeric($elements[$k])) {
                            $elements[$k] = (double) $elements[$k];
                        } else {
                            $l = strtolower($elements[$k]);
                            if ($l === 'true' || $l === 'on') {
                                $elements[$k] = true;
                            } elseif ($l === 'false' || $l === 'off') {
                                $elements[$k] = false;
                            } elseif ($l === 'null') {
                                $elements[$k] = null;
                            }
                        }
                    }
                }
                if ($tokenType === 0) {
                    $this->raiseError('Expected \';\' or \'{\'');
                } elseif ($tokenType === static::T_VAR) {
                    $name = str_replace('-', '', strtolower($elements[0]));
                    if (sizeof($elements) > 2) {
                        $value = array_slice($elements, 1);
                    } else {
                        $value = isset($elements[1]) ? $elements[1] : null;
                    }
                    $scope = $this->getCurrentScope();
                    if ($name === 'include') {
                        if (!is_array($value)) {
                            $value = [$value];
                        }
                        foreach ($value as $path) {
                            if (substr($path, 0, 1) !== '/') {
                                $path = 'conf/' . $path;
                            }
                            $files = glob($path);
                            if ($files) {
                                foreach ($files as $fn) {
                                    try {
                                        static::parse($fn, $scope, true);
                                    } catch (InfiniteRecursion $e) {
                                        $this->raiseError('Cannot include \'' . $fn . '\' as a part of itself, it may cause an infinite recursion.');
                                    }
                                }
                            }
                        }
                    } else {
                        if (sizeof($elements) === 1) {
                            $value = true;
                            $elements[1] = true;
                            $elTypes[1] = static::T_CVALUE;
                        } elseif ($value === null) {
                            $value = null;
                            $elements[1] = null;
                            $elTypes[1] = static::T_CVALUE;
                        }
                        if (isset($scope->{$name})) {
                            if ($scope->{$name}->source !== 'cmdline') {
                                if ($elTypes[1] === static::T_CVALUE && is_string($value)) {
                                    $scope->{$name}->pushHumanValue($value);
                                } else {
                                    $scope->{$name}->pushValue($value);
                                }
                                $scope->{$name}->source = 'config';
                                $scope->{$name}->revision = $this->revision;
                            }
                        } elseif ($scope instanceof Section) {
                            $scope->{$name} = new Generic();
                            $scope->{$name}->source = 'config';
                            $scope->{$name}->revision = $this->revision;
                            $scope->{$name}->pushValue($value);
                            $scope->{$name}->setValueType($value);
                        } else {
                            $this->raiseError('Unrecognized parameter \'' . $name . '\'');
                        }
                    }
                } elseif ($tokenType === static::T_BLOCK) {
                    $scope = $this->getCurrentScope();
                    $sectionName = implode('-', $elements);
                    $sectionName = strtr($sectionName, '-. ', ':::');
                    if (!isset($scope->{$sectionName})) {
                        $scope->{$sectionName} = new Section();
                    }
                    $scope->{$sectionName}->source = 'config';
                    $scope->{$sectionName}->revision = $this->revision;
                    $this->state[] = [static::T_ALL, $scope->{$sectionName}];
                }
            } else {
                $this->raiseError('Unexpected char \'' . Debug::exportBytes($c) . '\'');
            }
        }];
        for (; $this->p < $this->length; ++$this->p) {
            $c = $this->getCurrentChar();
            $e = end($this->state);
            $this->token($e[0], $c);
        }
        if (!$included) {
            $this->purgeScope($this->target);
        }
        if (Daemon::$config->verbosetty->value) {
            Daemon::log('Loaded config file: ' . escapeshellarg($file));
        }
    }