Еще даже не закончилось голосование за стандарт PSR-16 а PHPixie уже его поддерживает. Казалось бы кэширование настолько уже обработанная сфера, что тут уже нечем и удивить, но надеюсь прочитав статью вы найдете в PHPixie Cache для себя что-то новое и полезное. Как всегда в конце статьи вас ждет инструкция по использованию Cache без фреймворка и также информация о том как расширить компонент и помочь проекту.
Настройка
Сразу можно быстро пройтись по поддерживаемым драйверам. Пока их всего пять: void, memory, phpfile, memcached и redis.
// /assets/config/cache.php return [ // Описываем доступные хранилища 'default' => [ // Ничего не сохраняет 'driver' => 'void' ], 'second' => [ // Данные сохраняются в простом массиве в памяти 'driver' => 'memory', /* Опционально */ /** * Время жизни по умолчанию, может быть задано в секундах * или в значениях DateInterval (например P1D это 1 день). * По умолчанию null, то есть хранить вечно */ 'defaultExpiry' => 10, /** * Число между 1 и 1000, которое определяет * частоту сборки мусора. Чем оно выше тем чаще. * По умолчанию 10, то есть примерно 1% всех запросов * приведет к запуску сборки. */ 'cleanupProbability' => 10 ], 'third' => [ // Сохраняет в .php файлы 'driver' => 'phpfile', // Путь относительно /assets/cache 'path' => 'third', /* Опционально */ 'defaultExpiry' => null, 'cleanupProbability' => 10 ], 'fourth' => [ // Memcached 'driver' => 'memcached', /** * Тот же формат что к вызову метода Memcached::addServers, * но порт и вес можно не указывать, по умолчанию будут 1211 и 1 */ 'servers' => [ ['127.0.0.1'] ], /* Опционально */ 'defaultExpiry' => null ], 'fifth' => [ // Redis через пакет Predis 'driver' => 'redis', // Тот же формат что к конструктору Predis\Client 'connection' => array( 'scheme' => 'tcp', 'host' => '127.0.0.1', 'port' => 6379 ), /* Опционально */ 'defaultExpiry' => null ] ];
Использование
Как и говорится в заголовке PHPixie Cache поддерживает PSR-6 и новый упрощенный PSR-16, вот как выглядит интерфейс PHPixie\Cache\Pool с которым мы будем часто встречаться:
namespace PHPixie\Cache; use PHPixie\Cache\Pool\Prefixed; use Psr\Cache\CacheItemPoolInterface; use Psr\SimpleCache\CacheInterface; // Наследуем у PSR-6 и PSR-16 interface Pool extends CacheItemPoolInterface, CacheInterface { /** * Создает PSR-6 Item без получения его из кеша * @param string $key * @param mixed $value * @return Item */ public function createItem($key, $value = null); /** * Создает виртуальный Pool с фиксированным префиксом. * Об этом чуть позже. * @param string $prefix * @return Prefixed */ public function prefixedPool($prefix); }
И теперь сами примеры использования:
// Получаем одно из хранилищ. $storage = $cache->storage('second'); // PSR-6 public function getFairies() { $item = $this->storage->getItem('fairies'); if (!$item->isHit()) { $fairies = $this->generateFairies(); $item->set($fairies); $item->expiresAfter(100); $this->storage->save($item); } return $item->get(); } // PSR-16 public function getFairies() { $fairies = $this->storage->get('fairies'); if($fairies === null) { $fairies = $this->buildFairies(); $this->storage->set('fairies', $fairies, 100); } return $fairies; }
Впрочем нет смысла переписывать здесь работу с этими PSR-ами так как документации к ним и так полно, а если вы используете PHPStorm то подсказки вам все покажут.
Интересные фичи
Теперь о том, чем PHPixie Cache отличается от других библиотек.
Префиксные пулы
Когда несколько частей приложения пишут в тот же кэш чтобы избежать коллизий приходится придумывать уникальные префиксы для ключей. Как часто вам приходилось писать такой код:
$key = 'article-'.$id; $article = $cache->get($key);
Если те же сущности кэшируются в разных частях приложения надо следить за тем чтобы всегда использовать тот-же префикс или выносить эту логику в отдельный класс. В PHPixie Cache эта проблема решается префиксным пулом, который проксирует запросы в хранилище автоматически добавляя префикс.
$storage = $cache->storage('default'); $articlesPool = $storage->prefixedPool('article'); $articlesPool->set($article->id, $article->html()); // то же самое что $storage ->set('article.'.$article->id, $article->html());
Как вы наверное уже догадались $articlesPool имплементирует тот же интерфейс PHPixie\Cache\Pool что и хранилище и его тоже можно префиксить создавая иерархию. Это удобно тем что в будущем, когда статей станет много, такой префиксный пул можно заменить реальным отдельным хранилищем не переписывая код. Таким образом можно навсегда избавить себя от проблемы с ключами и префиксами.
Сам PHPixie\Cache это тоже Pool
У большинства пользователей скорее всего будет только одно хранилище для кэша, так почему бы не упростить им жизнь?
// вместо $cache->storage('default')->get('fairy'); // можно просто $cache->get('fairy');
При сохранении в файлы ключи не хешируються
Большинство библиотек генерируют имя файла делая хеш ключа. Это делается для того чтобы избежать проблем с кодировкой если вам вздумается задать ключ кракозябрами, но такое делать не рекомендуется в принципе. С другой стороны это хеширование занимает время процессора, так что особой причины оставлять его нет. Впрочем в планах есть добавить опцию включения этой функции параметром, для тех кому это критично.
Оптимизация кэширования в файлы
Опять же много библиотек используют сериализацию как формат файлов кэша. При этом сериализуется само значение и срок его годности. Тут минусов два: чтобы проверить срок годности надо прочитать и десериализовать весь файл и то что сама десериализация тоже недешевая для больших значений. Что же делает PHPixie\Cache? Посмотрим пример созданного файла:
<?php /*1483041355*/ return array(1,2,3);
В первой строке находится срок годности файла, так что для проверки его свежести достаточно считать только ее а не весь файл. К тому же данные из файла получаются оператором include
и поэтому код файла попадет в opcache, так что получение данных из него несколько раз подряд на самом деле не будет считывать его с диска пока он не изменится. Кстати старый подход с сериализацией тоже будет скоро доступен в компоненте.
Использование без фреймворка
$slice = new \PHPixie\Slice(); $filesystem = new \PHPixie\Filesystem(); $config = $slice->arrayData([ 'default' => [ 'driver' => 'memory' ] ]); // /tmp/cache будет корневой папкой // относительно которой будут прописываться пути $root = $filesystem->root('/tmp/cache/'); $cache = new \PHPixie\Cache($config, $root); // А если вы не собираетесь использовать кеш в файлы, то можно просто $cache = new \PHPixie\Cache($config);
Как видите обязательная зависимость только одна, так что если вы ищете простой и понятный кэш то надеюсь вам понравиться.
Добавление драйверов
После того как силами сообщества к PHPixie Social добавилось четыре новых провайдера я решил что пора добавлять небольшой чеклист о том как добавить свой драйвер в пакет:
- Создать класс
\PHPixie\Cache\Drivers\Type\YourDriver
унаследовав от\PHPixie\Cache\Drivers\Driver
. - Прописать его в
\PHPixie\Cache\Builder::$driverMap
. - Добавить тест
\PHPixie\Tests\Cache\Driver\YourDriverTest
унаследовав отPHPixie\Tests\Cache\DriverTest
и прописав в нем тестовый конфиг. - Подправить
.travis.yml
иcomposer.json
если есть какие-то новые зависимости. - Отправить Pull Request 😉
Если что, то мы всегда рады помочь с любыми проблемами в нашем чате.
ссылка на оригинал статьи https://habrahabr.ru/post/318778/
Добавить комментарий