【问题标题】:Using a keyword as variable name in an INI file在 INI 文件中使用关键字作为变量名
【发布时间】:2011-09-02 20:00:06
【问题描述】:

我在一个 INI 文件中有以下内容:

[country]
SE = Sweden
NO = Norway
FI = Finland

但是,当 var_dump() 执行 PHP 的 parse_ini_file() 函数时,我得到以下输出:

PHP Warning:  syntax error, unexpected BOOL_FALSE in test.ini on line 2
in /Users/andrew/sandbox/test.php on line 1
bool(false)

似乎保留了“NO”。有没有其他方法可以设置一个名为“NO”的变量?

【问题讨论】:

    标签: php variables config ini


    【解决方案1】:

    另一个技巧是用它们的值反转你的 ini 键并使用array_flip

    <?php
    
    $ini =
    "
        [country]
        Sweden = 'SE'
        Norway = 'NO'
        Finland = 'FI'
    ";
    
    $countries = parse_ini_string($ini, true);
    $countries = array_flip($countries["country"]);
    echo $countries["NO"];
    

    如果你这样做,你仍然需要在 NO 周围使用引号(至少)

    Norway = NO
    

    您不会收到错误消息,但 $countries["NO"] 的值将是一个空字符串。

    【讨论】:

    • 谢谢,这可能是唯一的方法。
    • 如果您的价值观不是唯一的,这不会中断吗?毕竟它们是,而不是键。
    • 我假设这里是这种情况,@Pacerier 因为我们正在谈论国家及其短代码。
    【解决方案2】:

    这可能来得有点晚,但 PHP parse_ini_file 的工作方式让我非常困扰,以至于我编写了自己的小解析器。

    随意使用它,但小心使用它只是经过浅层测试!

    // the exception used by the parser
    class IniParserException extends \Exception {
    
        public function __construct($message, $code = 0, \Exception $previous = null) {
            parent::__construct($message, $code, $previous);
        }
    
        public function __toString() {
            return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
        }
    
    }
    
    // the parser
    function my_parse_ini_file($filename, $processSections = false) {
        $initext = file_get_contents($filename);
        $ret = [];
        $section = null;
        $lineNum = 0;
        $lines = explode("\n", str_replace("\r\n", "\n", $initext));
        foreach($lines as $line) {
            ++$lineNum;
    
            $line = trim(preg_replace('/[;#].*/', '', $line));
            if(strlen($line) === 0) {
                continue;
            }
    
            if($processSections && $line{0} === '[' && $line{strlen($line)-1} === ']') {
                // section header
                $section = trim(substr($line, 1, -1));
            } else {
                $eqIndex = strpos($line, '=');
                if($eqIndex !== false) {
                    $key = trim(substr($line, 0, $eqIndex));
                    $matches = [];
                    preg_match('/(?<name>\w+)(?<index>\[\w*\])?/', $key, $matches);
                    if(!array_key_exists('name', $matches)) {
                        throw new IniParserException("Variable name must not be empty! In file \"$filename\" in line $lineNum.");
                    }
                    $keyName = $matches['name'];
                    if(array_key_exists('index', $matches)) {
                        $isArray = true;
                        $arrayIndex = trim($matches['index']);
                        if(strlen($arrayIndex) == 0) {
                            $arrayIndex = null;
                        }
                    } else {
                        $isArray = false;
                        $arrayIndex = null;
                    }
    
                    $value = trim(substr($line, $eqIndex+1));
                    if($value{0} === '"' && $value{strlen($value)-1} === '"') {
                        // too lazy to check for multiple closing " let's assume it's fine
                        $value = str_replace('\\"', '"', substr($value, 1, -1));
                    } else {
                        // special value
                        switch(strtolower($value)) {
                            case 'yes':
                            case 'true':
                            case 'on':
                                $value = true;
                                break;
                            case 'no':
                            case 'false':
                            case 'off':
                                $value = false;
                                break;
                            case 'null':
                            case 'none':
                                $value = null;
                                break;
                            default:
                                if(is_numeric($value)) {
                                    $value = $value + 0; // make it an int/float
                                } else {
                                    throw new IniParserException("\"$value\" is not a valid value! In file \"$filename\" in line $lineNum.");
                                }
                        }
                    }
    
                    if($section !== null) {
                        if($isArray) {
                            if(!array_key_exists($keyName, $ret[$section])) {
                                $ret[$section][$keyName] = [];
                            }
                            if($arrayIndex === null) {
                                $ret[$section][$keyName][] = $value;
                            } else {
                                $ret[$section][$keyName][$arrayIndex] = $value;
                            }
                        } else {
                            $ret[$section][$keyName] = $value;
                        }
                    } else {
                        if($isArray) {
                            if(!array_key_exists($keyName, $ret)) {
                                $ret[$keyName] = [];
                            }
                            if($arrayIndex === null) {
                                $ret[$keyName][] = $value;
                            } else {
                                $ret[$keyName][$arrayIndex] = $value;
                            }
                        } else {
                            $ret[$keyName] = $value;
                        }
                    }
                }
            }
        }
    
        return $ret;
    }
    

    它有什么不同?变量名只能由字母数字字符组成,但除此之外没有限制。字符串必须用 " 封装,其他所有内容都必须是特殊值,例如 noyestruefalseonoffnullnone。有关映射,请参见代码。

    【讨论】:

      【解决方案3】:

      有点小技巧,但您可以在键名周围添加反引号:

      [country]
      `SE` = Sweden
      `NO` = Norway
      `FI` = Finland
      

      然后像这样访问它们:

      $result = parse_ini_file('test.ini');
      echo "{$result['`NO`']}\n";
      

      输出:

      $ php test.php
      Norway
      

      【讨论】:

      • 这与将变量重命名为其他名称没有什么不同。使用您的解决方案,变量名称是“NO”,而不是 NO。也可以在配置文件中使用πNOπ = Norway
      【解决方案4】:

      当字符串中存在单引号组合(例如 't 或 's)时,我收到此错误。为了解决这个问题,我将字符串用双引号括起来:

      之前:

      You have selected 'Yes' but you haven't entered the date's flexibility
      

      之后:

      "You have selected 'Yes' but you haven't entered the date's flexibility"
      

      【讨论】:

        【解决方案5】:

        我遇到了同样的问题,并试图以各种可能的方式逃避这个名字。

        然后我记得由于 INI 语法,名称和值都会被修剪,因此以下解决方法可能应该可以解决问题:

        NL = Netherlands
        ; A whitespace before the name
         NO = Norway
        PL = Poland
        

        它有效;)只要您的同事阅读 cmets(并非总是如此)并且不要意外删除它。所以,是的,数组翻转解决方案是一个安全的选择。

        【讨论】:

          【解决方案6】:

          来自parse_ini_file 的手册页:

          有些保留字不能用作 ini 文件的键。其中包括:null、yes、no、true、false、on、off、none。

          所以不,你不能设置变量NO

          【讨论】:

            猜你喜欢
            • 2021-09-11
            • 1970-01-01
            • 2016-10-24
            • 2019-12-01
            • 2018-10-30
            • 1970-01-01
            • 1970-01-01
            • 2017-01-15
            相关资源
            最近更新 更多