【问题标题】:Parsing an "advanced" INI file with PHP使用 PHP 解析“高级”INI 文件
【发布时间】:2011-03-15 14:31:40
【问题描述】:

基本上,我想要一种简单、简单、单文件的方法来解析具有“高级”功能的 INI 文件,例如部分继承和属性嵌套,例如 Zend_Config_Ini

例如:

[foo]
a = 1
b.a = 2
b.b = 3
b.c = 4
c = 5

[bar : foo]
b.b = 17
c = 42

会解析成

array(
  'foo'=>array(
    'a'=>'1',
    'b'=>array(
      'a'=>'2',
      'b'=>'3',
      'c'=>'4'
    ),
    'c'=>'5'
  ),
  'bar'=>array(
    'a'=>'1',
    'b'=>array(
      'a'=>'2',
      'b'=>'17',
      'c'=>'4'
    ),
    'c'=>'42'
  )
)

PHP 的内置 parse_ini_file,除了带有简单部分和简单键的简单 INI 之外不处理任何其他内容。

我使用Zend_Config_Ini 的问题是我必须包含几乎整个 Zend_Config 子包,并且超级臃肿且可配置。

是否有一个 smallsimple 库可用于解析这个?
如果没有,是否有我没有看到的简单实现?

我所说的小而简单,是指 INI 文件的 sfYaml。

在我(非常缺乏经验的)眼中,我必须使用 parse_ini_file 解析一次,然后返回并解决继承问题,然后遍历每个部分并递归扩展键...

更新:由于这似乎是一个热门问题,我想注意I have a simple class implementing this on GitHub,请随时发送拉取请求、问题等。

【问题讨论】:

  • 你能解释一下为什么 Zend_Config_* 是“超级臃肿”吗?哦,你不需要整个树......只需 Zend_Config、Zend_Config_Exception 和 Zend_Exception
  • 查看源文件,Zend_Config_Ini 依赖于 Zend_Config_Exception 和 Zend_Config。 Zend_Config_Exception 依赖于 Zend_Exception。所有功能都分布在多个类和文件中。诚然,我对采埃孚的 OOP 设计非常高度重视,但在这种情况下,它确实太过分了。
  • 我想要它做的就是将一个 ini 解析为一个关联数组。我不想要或不需要 Zend_Config 具有的额外功能。
  • 如果你想以艰难的方式来做,你可以选择 :) 虽然你可以对 Zend_Config_Ini 做一些小的修改来移除依赖。
  • 我不会称 Zend_Config 臃肿。臃肿意味着过度功能,这反过来又意味着功能。我们谈论的是 Zend“构建你自己的 ACL 实现!”框架在这里。

标签: php parsing ini


【解决方案1】:

另一个选项 - 这是对,构建和解析。

function build_ini_string_nested( $data, $path = null ){
  $content = array();
  foreach( $data AS $key => $val ){
    if( is_array($val) ){
      $content[] = build_ini_string_nested( $val, ($path ? $path. '.' : '') . $key );
    }
    else if( $path ) {
      $content[] = $path . '[' . ($path && is_numeric($key) ? '' : $key) . '] = ' . $val;
    }
    else {
      $content[] = $key . ' = ' . $val;
    }
  }
  return implode("\n", $content);
}

function parse_ini_string_nested( $data, $path = null ){
  if( is_string($data) )
    $data = parse_ini_string($data);
  if( $path )
    foreach( $data AS $key => $val ){
      if( strpos( $key, $path.'.' ) !== false ){
        $find_node = explode('.', $path);
        $this_path = reset(explode('.', substr($key, strlen($path.'.'))));
        $node =& $data;
        do {
          $node =& $node[ array_shift($find_node) ];
        } while( count($find_node) );
        if( is_array($node[ $this_path ]) ){
          $node[ $this_path ][] = $val;
        }
        else {
          $node[ $this_path ] = $val;
        }
      }
    }
  else {
    $drop_keys = array();
    foreach( $data AS $key => $val ){
      if( count(explode('.', $key)) > 1 ){
        $path = reset(explode('.', $key));
        $data[ $path ] = array();
        $data = parse_ini_string_nested( $data, $path );
        $drop_keys[] = $key;
      }
    }
    foreach( $drop_keys AS $key ){
      unset($data[ $key ]);
    }
  }
  return $data;
}

【讨论】:

    【解决方案2】:

    我已经写了这样的东西,现在它对我来说还可以:

            $config = array();
            $configSrc = parse_ini_file( $filePath, true );
            foreach( $configSrc as $sectionName => $section )
            {
                $config[$sectionName] = array();
                foreach( $section as $itemName => $item )
                {
                    $itemNameArray = explode( '.', $itemName );
                    eval( sprintf('$config[$sectionName][\'%s\'] = $item;', join("']['", $itemNameArray)) );
                }
            }
    
            // marge inheritance;
            foreach( $config as $sectionName => $section )
            {
                $ancestryArray = explode( ':', $sectionName );
                $ancestryCount = count( $ancestryArray );
                if( $ancestryCount > 1 )
                { //
                    $config[$sectionNameTrimmed = trim($ancestryArray[0])] = array();
                    $ancestryArray = array_reverse( array_slice($ancestryArray, 1) );
                    foreach( $ancestryArray as $ancestryName )
                    {
                        $ancestryName = trim( $ancestryName );
                        if( isset($config[$ancestryName]) ) {
                            $config[$sectionNameTrimmed] = array_replace_recursive( $config[$sectionNameTrimmed], $config[$ancestryName] );
                        }
                    }
    
                    $config[$sectionNameTrimmed] = array_replace_recursive( $config[$sectionNameTrimmed], $section );
                    unset( $config[$sectionName] );
                }
    
            }
    

    【讨论】:

      【解决方案3】:

      不确定我应该编辑旧答案还是添加新答案。

      试试这个版本,应该是你要找的。​​p>

      function parse_ini_advanced($array) {
          $returnArray = array();
          if (is_array($array)) {
              foreach ($array as $key => $value) {
                  $e = explode(':', $key);
                  if (!empty($e[1])) {
                      $x = array();
                      foreach ($e as $tk => $tv) {
                          $x[$tk] = trim($tv);
                      }
                      $x = array_reverse($x, true);
                      foreach ($x as $k => $v) {
                          $c = $x[0];
                          if (empty($returnArray[$c])) {
                              $returnArray[$c] = array();
                          }
                          if (isset($returnArray[$x[1]])) {
                              $returnArray[$c] = array_merge($returnArray[$c], $returnArray[$x[1]]);
                          }
                          if ($k === 0) {
                              $returnArray[$c] = array_merge($returnArray[$c], $array[$key]);
                          }
                      }
                  } else {
                      $returnArray[$key] = $array[$key];
                  }
              }
          }
          return $returnArray;
      }
      function recursive_parse($array)
      {
          $returnArray = array();
          if (is_array($array)) {
              foreach ($array as $key => $value) {
                  if (is_array($value)) {
                      $array[$key] = recursive_parse($value);
                  }
                  $x = explode('.', $key);
                  if (!empty($x[1])) {
                      $x = array_reverse($x, true);
                      if (isset($returnArray[$key])) {
                          unset($returnArray[$key]);
                      }
                      if (!isset($returnArray[$x[0]])) {
                          $returnArray[$x[0]] = array();
                      }
                      $first = true;
                      foreach ($x as $k => $v) {
                          if ($first === true) {
                              $b = $array[$key];
                              $first = false;
                          }
                          $b = array($v => $b);
                      }
                      $returnArray[$x[0]] = array_merge_recursive($returnArray[$x[0]], $b[$x[0]]);
                  } else {
                      $returnArray[$key] = $array[$key];
                  }
              }
          }
          return $returnArray;
      }
      

      会这样称呼:

      $array = parse_ini_file('test.ini', true);
      $array = recursive_parse(parse_ini_advanced($array));
      

      这可以做得更好/更清晰,但对于一个简单的解决方案,它应该工作得很好。

      如果你的配置是:

      [foo]
      a = 1
      b.a = 2
      b.b = 3
      b.c = 4
      c = 5
      
      [bar : foo]
      b.x.c = 33
      b.b = 17
      c = 42
      
      [hot : bar : foo]
      b.a = 83
      b.d = 23
      

      输出应该是:

      Array
      (
      [foo] => Array
          (
              [a] => 1
              [b] => Array
                  (
                      [a] => 2
                      [b] => 3
                      [c] => 4
                  )
      
              [c] => 5
          )
      
      [bar] => Array
          (
              [a] => 1
              [b] => Array
                  (
                      [a] => 2
                      [b] => 17
                      [c] => 4
                      [x] => Array
                          (
                              [c] => 33
                          )
      
                  )
      
              [c] => 42
          )
      
      [hot] => Array
          (
              [a] => 1
              [b] => Array
                  (
                      [a] => 83
                      [b] => 17
                      [c] => 4
                      [x] => Array
                          (
                              [c] => 33
                          )
      
                      [d] => 23
                  )
      
              [c] => 42
          )
      )
      

      【讨论】:

      • 嘿,谢谢!这正是我正在寻找的。我不可能如此简洁地提出这个问题。供将来参考,因为它是对您其他答案的修正,您应该对其进行编辑。
      • 我知道这是一篇旧帖子,但仍然有用,尽管 recursive_parse 函数存在错误。在第二个 foreach 中,在第一个循环之后 $b = array($v => $b); $b 将不会被设置。如果 $b 未设置,递归合并将在 $b[$x[0]] 上失败
      【解决方案4】:

      首先回答一件事,属性嵌套可以从 parse_ini_file() 中获得,将第二个参数设置为 true 即 parse_ini_file('test.ini', true);这将为您提供一个多维数组,即

      Array
      (
          [foo] => Array
              (
                  [a] => 1
                  [b.a] => 2
                  [b.b] => 3
                  [b.c] => 4
                  [c] => 5
              )
      
          [bar : foo] => Array
              (
                  [b.b] => 17
                  [c] => 42
              )
      )
      

      这是一个小函数,它将解析 parse_ini_file() 返回的数组并将其转换为类别。

      /**
       * Parse INI files Advanced
       * process_sections = true
       * scanner_mode = default
       * 
       * Supports section inheritance
       * and has property nesting turned on
       * 
       * @param string $filename
       * return array
       */
      function parse_ini_file_advanced($filename) {
          $array = parse_ini_file($filename, true);
          $returnArray = array();
          if (is_array($array)) {
              foreach ($array as $key => $value) {
                  $x = explode(':', $key);
                  if (!empty($x[1])) {
                      $x = array_reverse($x, true);
                      foreach ($x as $k => $v) {
                          $i = trim($x[0]);
                          $v = trim($v);
                          if (empty($returnArray[$i])) {
                              $returnArray[$i] = array();
                          }
                          if (isset($array[$v])) {
                              $returnArray[$i] = array_merge($returnArray[$i], $array[$v]);
                          }
                          if ($k === 0) {
                              $returnArray[$i] = array_merge($returnArray[$i], $array[$key]);
                          }
                      }
                  } else {
                      $returnArray[$key] = $array[$key];
                  }
              }
          } else {
              return false;
          }
      
          return $returnArray;
      }
      

      它会返回这个:

      Array
      (
          [foo] => Array
              (
                  [a] => 1
                  [b.a] => 2
                  [b.b] => 3
                  [b.c] => 4
                  [c] => 5
              )
      
          [bar] => Array
              (
                  [a] => 1
                  [b.a] => 2
                  [b.b] => 17
                  [b.c] => 4
                  [c] => 42
              )
      )
      

      最后写入获胜,即
      [bar2:foo2:bar:foo]
      bar2 以其自己的数组中的设置获胜
      注意:其他 3 个阵列将在那里。

      希望这就是你要找的。​​p>

      【讨论】:

      • 好吧,你所说的属性嵌套只是部分([foo][foo : bar])。您的函数处理部分继承(非常好,我可能会添加),但不是我的意思的属性嵌套:b.a = 5 应该生成 [b]=>Array([a]=>5)
      猜你喜欢
      • 2015-10-13
      • 2016-02-07
      • 1970-01-01
      • 2014-09-03
      • 2012-11-18
      • 1970-01-01
      • 2012-09-23
      • 2011-10-24
      • 1970-01-01
      相关资源
      最近更新 更多