Класс для работы с Ini файлами

Beginner.83

Новичок
Написал класс для работы с Ini файлом хотелось бы общественной критики:
PHP:
class Ini_Exception extends Exception {}

class Ini implements ArrayAccess, Countable
{
    private static $instance; 
    
    private $autosave = false;
    
    private $ext = '.ini';
    
    private $delimiter;
    
    private $file;
    
    private $data;
    
    public function __construct($file, $delimiter='.', $autocreate=false)
    {
        if ($autocreate && !file_exists($file.$this->ext))
            file_put_contents($file.$this->ext, '');
        $this->file = realpath($file.$this->ext);
        $this->data = parse_ini_file($this->file, 1);
        $this->delimiter = $delimiter;
    }
    
    public static function factory($file=null, $delimiter='.', $autocreate=false)
    {
        if (!self::$instance && $file)
            self::$instance = new self($file, $delimiter, $autocreate);
        return self::$instance;
    }
    
    public function setAutosave($status=false)
    {
        if (!is_bool($status))
            throw new Ini_Exception('Invalid parameter data type');
        $this->autosave = $status;
        return $this;
    }

    public function getAutosaveStatus()
    {
        return $this->autosave;
    }
    
    public function get($path=null)
    {
        if (!$path) return $this->data;
        $path = explode($this->delimiter, $path);
        if (count($path) == 1){
            return isset($this->data[$path[0]]) ? $this->data[$path[0]] : null; 
        }
        elseif (count($path) == 2){
            return isset($this->data[$path[0]][$path[1]]) ? $this->data[$path[0]][$path[1]] : null;
        }
    }
    
    public function set($path, $value)
    {
        $path = explode($this->delimiter, $path);
        if (count($path) == 1){
            if (!is_array($value))
                throw new Ini_Exception('Incorrect data type values');
            $this->data[$path[0]] = $value; 
        }
        elseif (count($path) == 2){
            if (is_array($value) || is_object($value))
                throw new Ini_Exception('Incorrect data type values');
            $this->data[$path[0]][$path[1]] = $value;
        }
        
        if ($this->autosave)
            $this->save();
        
        return $this;
    }
    
    public function del($path)
    {
        if (!$path) return $this->data;
        $path = explode($this->delimiter, $path);
        if (count($path) == 1){
            unset($this->data[$path[0]]); 
        }
        elseif (count($path) == 2){
            unset($this->data[$path[0]][$path[1]]);
        }
        
        if ($this->autosave)
            $this->save();
        
        return $this;
    }
    
    public function is($path)
    {
        if (!$path) return $this->data;
        $path = explode($this->delimiter, $path);
        if (count($path) == 1){
            return isset($this->data[$path[0]]); 
        }
        elseif (count($path) == 2){
            return isset($this->data[$path[0]][$path[1]]);
        }
    }
    
    public function size($path)
    {
        if (!$path) return $this->data;
        $path = explode($this->delimiter, $path);
        if (count($path) !== 1)
            throw new Ini_Exception('Incorrect path');
        
        return count($this->data[$path[0]]); 
    }
    
    public function offsetExists($offset)
    {
        return $this->is($offset);
    }
    
    public function offsetGet($offset)
    {
        return $this->get($offset);
    }
    
    public function offsetSet($offset, $value)
    {
        $this->set($offset, $value);
    }
    
    public function offsetUnset($offset)
    {
        $this->del($offset);
    }
    
    public function count()
    {
        return count($this->data);
    }
    
    public function save()
    {
        $str = '';
        foreach ($this->data as $k=>$v){
            $str .= "[$k]\n";
            if (is_array($v)){
                foreach($v as $k_=>$v_){
                    $str .= "$k_=$v_\n";
                }
            }
        }
        file_put_contents($this->file, $str);
    }
}
 

Ярослав

Новичок
В конструкторе можно переопределить параметр $delimiter например на |
Тут имелось ввиду вложенность
Тоисть может быть вложенность 4 a.b.c.d = 1
А в скрипте дожно быть
PHP:
array(
    'a' => array(
        'b'   => array(
            'c'   => array(
                'd' => 1
            )
        )
    )
)
А у вас, насколько я понял, только возможна вложенность 2 уровня
PHP:
public function get($path=null)
    {
        if (!$path) return $this->data;
        $path = explode($this->delimiter, $path);
        if (count($path) == 1){
            return $this->data[$path[0]]; 
        }
        elseif (count($path) == 2){
            return $this->data[$path[0]][$path[1]];  // максимум 2
        }
    }
Какой смысл в функции:
PHP:
public static function newFile($filename)
UPD:
Упс, недопер, тут вообще вложенность не предусмотрена. Ключи в первом массиве - это секции.
 

Beginner.83

Новичок
Тут имелось ввиду вложенность
Тоисть может быть вложенность 4 a.b.c.d = 1
А в скрипте дожно быть
PHP:
array(
    'a' => array(
        'b'   => array(
            'c'   => array(
                'd' => 1
            )
        )
    )
)
А у вас, насколько я понял, только возможна вложенность 2 уровня
PHP:
public function get($path=null)
    {
        if (!$path) return $this->data;
        $path = explode($this->delimiter, $path);
        if (count($path) == 1){
            return $this->data[$path[0]]; 
        }
        elseif (count($path) == 2){
            return $this->data[$path[0]][$path[1]];  // максимум 2
        }
    }
Какой смысл в функции:
PHP:
public static function newFile($filename)
UPD:
Упс, недопер, тут вообще вложенность не предусмотрена. Ключи в первом массиве - это секции.
Внёс некоторые изменения в исходном коде.
 

Ирокез

бессмертный пони
Команда форума
Партнер клуба
Ярослав
Заимплементи ArrayAccess, Countable, удобнее
 

Beginner.83

Новичок
Ярослав
Заимплементи ArrayAccess, Countable, удобнее
С какой целью? В плане о каком удобстве идёт речь?
PHP:
//Объявление экземпляра класса
$Ini = new Ini(FCFG);


$Ini
    //Создание новой секции
    ->set('section', array('value'))
    //Добавление или переопределение ключа в секции
    ->set('section.key', 'value')
    //Сохранение данных в файле
    ->save();

//Получение значений по ключу
$Ini->get('section.key');
//Проверка на существование
$Ini->is('section.key');
//Удаление 
$Ini->del('section.key');
//Количество элементов в секции
$Ini->size('section');
О каком удобстве идёт речь? О?
PHP:
$Ini['section']['key'] = 'value'; //количество символов 32
$Ini->set('section.key','value');//количество символов 32
 

Ирокез

бессмертный пони
Команда форума
Партнер клуба
О каком удобстве идёт речь? О?
PHP:
$Ini['section']['key'] = 'value'; //количество символов 32
$Ini->set('section.key','value');//количество символов 32
умеляюсь

PHP:
$Ini['section.key'] = 'value'; //количество символов 30
это просто пипец :)

ой нет,

PHP:
$Ini['section.key']='value'; //количество символов 28
PHP:
count($Ini); 
unset($Ini['1']);
isset($Ini['1']);
привычные конструкции
 

Ирокез

бессмертный пони
Команда форума
Партнер клуба
grigori
угу, только если php >= 5.3
Действительно почему??

5.3.0 Added optional scanner_mode parameter. Single quotes may now be used around variable assignments. Hash marks (#) may no longer be used as comments and will throw a deprecation warning if used.
5.2.7 On syntax error this function will return FALSE rather than an empty array.
5.2.4 Keys and section names consisting of numbers are now evaluated as PHP integers thus numbers starting by 0 are evaluated as octals and numbers starting by 0x are evaluated as hexadecimals.
5.0.0 Values enclosed in double quotes can contain new lines.
4.2.1 This function is now affected by safe mode and open_basedir
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Ирокез
я сомневаюсь в целесообразности этого функционала,
не мог бы ты или автор привести реальную ситуацию, когда надо редактировать файл конфигурации средствами скрипта,
и при этом формат ini-файла лучше, чем сериализованный или экспортированный массив
 

Beginner.83

Новичок
Ирокез
не мог бы ты или автор привести реальную ситуацию, когда надо редактировать файл конфигурации средствами скрипта,
и при этом формат ini-файла лучше, чем сериализованный или экспортированный массив
Пример:
У нас есть конфигурационный файл хранящий в себе данные по сайту. Ну там настройки соединения с БД, Memcache ну и прочие сладости хранение которых недопустимо в БД.

К примеру требуется поменять некоторые параметры через человеко понятный интерфейс дабы ограничить доступ к исходникам. И тут на мой взгляд класс для работы с ini файлами вполне полезная штука. Я конечно новичок но необходимость по моему очевидна.

Ещё одно замечание по поводу почему именно Ini - формат данных понятен если заглянуть в исходники.
То есть есть возможность редактирования как через интерфейс так и через скрипт.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
и чем в твоем случае формат ini предпочтительнее простого экспортированного массива?
возможно, ты просто не задумывался об этом?
 

Ирокез

бессмертный пони
Команда форума
Партнер клуба
Ирокез
я сомневаюсь в целесообразности этого функционала,
не мог бы ты или автор привести реальную ситуацию, когда надо редактировать файл конфигурации средствами скрипта,
и при этом формат ini-файла лучше, чем сериализованный или экспортированный массив
мне абсолютно до фонаря, на кой этот функционал нужен ТК, я точно так-же как и ты считаю, что parse_ini... достаточно,
но ТК, конкретно определил функционал и попросил обсудить класс, а не на кой этот функционал нужен.

PS: Но ведь у нас принято, обсуждать не поставленный вопрос, а нахрена это нужно
 

Beginner.83

Новичок
умеляюсь

PHP:
$Ini['section.key'] = 'value'; //количество символов 30
это просто пипец :)

ой нет,

PHP:
$Ini['section.key']='value'; //количество символов 28
PHP:
count($Ini); 
unset($Ini['1']);
isset($Ini['1']);
привычные конструкции
Спасибо приму к сведению действительно конструкции более удобные.
 
Сверху