Итак, на хабре я прочитал что самый быстрый способ чтения конфигов — это чтение сериализованных данных. Работает быстрее остальных, не тормозит на больших объемах данных. Правда, при этом конфигурационные файлы править вручную достаточно сложно. (копипаста с хабры) Так вот, для себя написал небольшой класс для работы с такими данными, потому что в ручную мягко говоря слишком сложно редактировать такие данные (по крайней мере для меня) Вот сам класс Код (PHP): <?php /** * The MIT License (MIT) * * Copyright (c) 2014 Pixaye * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /** * Managing logs, if LOG_ENABLED = true, that logs are maintained, * If it's equals false, then respectively, while performing the action, it will not log the. */ define('LOG_ENABLED', false); class Gee { /** * @var array */ protected $_gee_file; /** * @param $file * @return bool|mixed */ public function _gee_load($file) { if (file_exists($file)) { //Return associative array return unserialize(file_get_contents($file)); } else { $this->_gee_file = $file; $this->_gee_file_error(); return false; } } /** * @param $file * @param array $arr * @return bool */ public function _gee_save($file, $arr = array()) { if (file_exists($file)) { $nc = file_get_contents($file); $sc = serialize($arr); if ($nc == $sc) { $this->_gee_log('File did not edited ' . $file . ' ,writing new file aborted!'); return false; } else { $this->_gee_file = $file; file_put_contents($file, serialize($arr)); $this->_gee_log('File ' . $file . ' successfully updated!'); return true; } } else { $this->_gee_log('File ' . $file . ' not found!'); $this->_gee_file = $file $this->_gee_file_error(); return false; } } /** * @return bool */ protected function _gee_file_error() { exit('File <b>'. $this->_gee_file. '</b> does not exist!'); } /** * @param null $msg * @return bool */ protected function _gee_log($msg = null) { if (LOG_ENABLED == true) { if (file_exists('logs/log.txt')) { if (filesize('logs/log.txt') > 10000000) { file_put_contents("logs/log.txt", ""); } if (!empty($msg)) { file_put_contents('logs/log.txt', date("F j, Y, g:i a, H:i:s") . ' :: ' . $msg . "\r\n", FILE_APPEND); return true; } else { return false; } } else { echo "Can't write in log, file does not exist!"; return false; } } else { return false; } } } Класс так же может вести логи, хотя я не уверен что они нужны но всё же, если поставить константе LOG_ENABLED значение true, то все действия будут логгироваться. Но для начала нужно создать папку logs, а в ней log.txt Парсинг файлов происходит следующим образом, вы просто должны вызвать метод _gee_load('путь к файлу'); Метод возвращает ассоциативный массив и работает быстро. Сохранение данных в файл производится методом _gee_save('путь к файлу', массив типа ключ=>значение); P.S. если файл существует и он не был изменен, а метод вызывается, то данные в файл не будут сохранены (типа я кеш изобрел, хотя куда мне). Расширение файлов: *.gee Делал для себя, т.к. мне нужна высокая скорость работы моего фреймворка. Так же очень важно поставить в папке с файлами .htaccess с Код (Text): deny from all или же если файл не в папке а скажем в корне сайта, то Код (Text): <Files "*.gee"> deny from all </Files> Go!
т.е. вручную менять конфиг нельзя, так как хранится он в сериализованном виде, тока через класс? чем json неустроил? или yaml какой нить. наглядно и быстро пашет
Ну работа с сериализированными данными быстрее чем с json и yaml Кто сказал что нельзя? Можно но придется немного помучатся
первое чтение да медленне на ямле, а потом результат ямла дампится в кеш в виде сериализованного массива и всё... единственное, нужно для дебаг режима настроить, чтобы перед чтением конфига из кеша, сверять дату модификации оригинального ямла... либо просто ручками очищать кеш на продакшине разумеется прямое чтение из кеша, притом кеш можно хранить даже не в файлах, а в томже APCu, Memcached, WinCache и т.д...
а зачем придумывать решение - которое заставляет мучаться? конфиг должен быть простой и наглядный. чтоб менять его можно было хоть руками, хоть программой. вариант с сериализацией - тупиковый. за мнимую производительность приходится платить полной потерей самой сути конфигурационного файла. ну подумайте. что есть конфиг? это место управления Человеком - Машины. т.е. конфиг пишется и редактируется - Человеком. он должен быть понятен Человеку, и только потом Машине. дарю идею - хранить конфиг в виде base64. это ваще будет модно)
А читал очень невнимательно и поверхностно. Читал бы менее поверхностно и более вдумчиво, да еще бы и с комментами, обратил бы внимание на то, что: 1) Во главу угла надо ставить удобство. 2) Чтобы добиться более-менее заметных при получении замеров расхождений, которые нельзя было бы списать на погрешность/просаживание процессора по левой причине, там использовались "конфиги" с сотнями и тысячами строк-параметров. 3) Конфиг парсится один раз. Хочется мегапроизводительности - составь конфиг из инструкций, пишущих его в шаредмемори. Но конфиг - это не тонкое место. Это разовая операция. Она всегда 100% предсказуема в плане потребления ресурсов. Никогда не просядет. Не породит утечки. Не имеет алгоритма, который можно отрефакторить. Это не то место, где стоит экономить микросекунды и килобайтики. По сути это статья про то, какой конь в вакууме быстрее летает, сферический или додекаэдрический. Оказалось, что сферический конь в вакууме действительно достигает точки назначения на 0.002 секунды быстрее. В реальных же условиях, на Земле, это не несет особой практической ценности. Удобство конфига для человека - это не просто блажь. Тривиальная ситуация - выгрузил проект с локалки на внешку, и все перестало работать, потому что: 1) хоумдиректори левое. 2) данные для бд левые. 3) основной домен левый. 4) прочие левые данные, специфичные для сервера. И все хорошо, но проект не работает, или работает неадекватно. И конфигуратор тоже может лежать кверху пузом. Разруливается это все предельно просто - поправил конфиг, перезалил, обновил страничку, воскричал "алилуйя!". Конфигураторы нужны, но работающие с удобными человеку конфигами. З.Ы. За старания - пять. Может для кого-то и будет полезным, кто знает.
если хранить конфиг в пхп-файле, то он будет и читаем, и редактируем, и кешируем опкешереами. и будет ацки быстро и ацки удобно. а для кеша данных, которые человеком не читаются, лучше конечно serialize, ибо он неимоверно быстрее всего остального.
Артём, Yaml работает намного медленнее чем тот же Ini который я использовал у себя. Среднее время выполнения скрипта с Ini - 0.0150s Тот же скрипт с Yaml (Symfony) - 0.0290s
Таки вот же жь. Я, к примеру, оч люблю генерируемые кеши и конфиги хранить именно в виде пых-файлов по тем же причинам. Вот там, если есть опкэшер, точно производительность и расход памяти значительно сокращаются. И не нужно ничего парсить. Не нужно создавать никакие структуры данных. Они уже созданы и подключаются прямо в пых в готовом виде - это же прекрасно! Кстати, в комментах к той статье на хабре тоже было подобное указано, как важное замечание в пользу "монструозных дефайнов" и конфигов в виде статик-класса для модных и массива для любителей боли, неприемлющих помощь со стороны IDE при поиске нужного параметра.
сериалайз работает очень быстро, а если "генерируемые" кеши не читаются людьми - то самое то именно сериалайз юзать.
при чем здесь кеши. речь шла о конфиге. сериалайз для конфига неприемлем. конфиг читается один раз - а потом тупо висит в памяти. кеш тут какбе и ненужен.
ну про отладочное речь не идёт. там что угодно можно делать. вот мои кешеры. на файлах быстрее, чем через мемкеш, но надо самому следить за переполнением. мемкеш: Код (PHP): <?php class Cache { private static $mc = null; private static function Init() { self::$mc = new Memcache(); foreach (CFG::$pincms['cache']['servers'] as $server) { self::$mc->addServer($server['host'], $server['port']); } return true; } public static function Get($hash) { if (is_null(self::$mc)) { if (self::Init() == false) { return false; } } // debug mode // $r = self::$mc->get($hash); // return $r; return self::$mc->get($hash); } public static function Set($hash, $content) { if (is_null(self::$mc)) { if (self::Init() == false) { return false; } } return self::$mc->set($hash, $content); } } на файликах: Код (PHP): <?php class Cache { private static $path = ''; private static $ok = false; public static function Init() { if (self::$ok === true) { return true; } PinCMS::$binhash = false; self::$path = ROOT . DS . 'filecache' . DS; if (!is_dir(self::$path)) { mkdir(self::$path); } if (touch(self::$path . 'test')) { self::$ok = true; } self::$ok = true; return self::$ok; } public static function Get($hash) { if (!self::Init()) { return false; } $fp = self::$path . $hash; if (!file_exists($fp)) { return false; } $content = file_get_contents(self::$path . $hash); if ($content === false) { return false; } return unserialize($content); } public static function Set($hash, $content) { if (!self::Init()) { return false; } $fp = self::$path . $hash; if (!touch($fp)) { return false; } $content = serialize($content); return file_put_contents(self::$path . $hash, $content); } } Cache::Init();
-я бы добавил возможность отключать кеширование. -еще добавил бы метод для удаления кеша по ключу. -еще бывает удобно если можно указать время жизни для элемента кеша. чтобы все само обновлялось когда таймаут просрочится. -еще путь сохранения для файлов надо читать из конфига, а не прописывать жестко внутри класса. -странный код: Код (PHP): if (touch(self::$path . 'test')) { self::$ok = true; } self::$ok = true; -еще несмогу иметь сразу два кешера с разными свойствами, ибо статики не к месту связывают по рукам и ногам это так на вскидку.
так результат ямл парсера скинь в кеш и будут такие же циферки как на "голом пхп" зато ямл использовать человеком удобней всего ,а у ini есть ограничения по вложенности.
Хм, вынужден не согласиться какая разница, написать: Код (Text): host = localhost или Код (Text): host: localhost Добавлено спустя 3 минуты 6 секунд: На Linux-е результаты получше, среднее время выполнения скрипта: 0.0022s (без APC) ,думаю с IIS будет тоже самое.
в ini всего 1 уровень вложенности Код (Text): [db] name: mybase в ямле можно хоть какую вложенность оформлять, а также записывать ассоциативные массивы в одну строчку, например: Код (Text): db: name: mybase cache: { result: apc, query: apc } да и много еще чего можно в ямле а с кешированием на "скорость" это удобство вообще никак не влияет.
У меня подключаемые компоненты используют метафайлы с уровнем вложенности больше 1. Например секция настроек, состоящая из подсекций, состоящих из подсекций, в зависимости от типа параметра. Но я для себя выбрал не YAML, а XML. Личное предпочтение. А вот для конфига системы в целом, вложенность имеет сомнительную ценность.
она реализована до них, поэтому я не делал ничего такого. у меня невозможно узнать ключ того, кого надо удалить. так что ой. я пытался, но это невозможно. изменение того, что я хочу кешировать приводит к изменению хеша и всё, поезд ушел. реализовано до кешера, опять же. может быть. в текущих условиях не требуется. походу дебаговая строка, которую я тупо забыл убрать. благодарствую. дык и не надо.