💢 Проблема с переходом на PHP7: Memcached
ПХП7 — огромный шаг для интерпретатора ПХП в плане производительности и потребления памяти, поэтому есть большой соблазн начать переводить на него свои продукты. К сожалению, возросшие показатели дались не бесплатно, а путём сломанной в некоторых местах обратной совместимости, самая яркая проблема, которая из этого вытекает — все модули без исключения надо модифицировать.
Поэтому этот шаг, к ПХП7 очень труден для больших проектов, вроде тех, который разрабатываем мы. Тем не менее, мы медленно, но верно движемся в финишу. Вчера столкнулись с неожиданной сложностью, на которую мне пришлось потратить вечер.
Оказалось, что в модуле Мемкешд для ПХП7 нет реализации получения токена cas в методах get и getMulti (наверняка нет ещё в каких-то), но мы их не используем. Это видно, например, по прототипу:
Method [ <internal:memcached> public method get ] {
- Parameters [2] {
Parameter #0 [ <required> $key ]
Parameter #1 [ <optional> $cache_cb ]
}
}
Как видите, параметра cas нет вообще (он должен быть последним). Это печальное обстоятельство подтолкнуло меня к исследованию и к ночи я сделал решение. Возможно кому-то пригодится:
class MemcachedPHP7
{
use \Core\ProxyTrait;
public function __construct($mc)
{
$this->setObject($mc);
}
public function get($key, callable $cache_cb = null, &$cas_token = null)
{
switch (func_num_args()) {
case 1:
return $this->obj->get($key);
case 2:
return $this->obj->get($key, $cache_cb);
default:
if ($this->obj->getDelayed([$key], true) === false) {
return false;
}
$res = $this->obj->fetchAll();
if ($res === false || !$res) {
if ($cache_cb !== null) {
if ($cache_cb($this->obj, $key, $value)) {
$this->obj->set($key, $value);
}
} else {
$value = false;
}
} else {
$cas_token = $res[0]['cas'];
$value = $res[0]['value'];
}
return $value;
}
}
public function getMulti(array $keys, array &$cas_tokens = null)
{
if (func_num_args() === 1) {
return $this->obj->getMulti($key);
} else {
if ($this->obj->getDelayed($keys, true) === false) {
return false;
}
$res = $this->obj->fetchAll();
if ($res === false) {
return false;
}
$cas_tokens = [];
$values = [];
$results = array_column($res, null, 'key');
foreach ($keys as $key) {
$cas_tokens[$key] = $results[$key]['cas'];
$values[$key] = $results[$key]['value'];
}
return $values;
}
}
}
Трейт ProxyTrait я тут не привожу, там идея простая — он тупо проксирует всё, что получает через магические методы __get, __set, __call и прочие, setObject — метод этого трейта. Очень удобно, если надо оставить всё как есть, за исключением каких-то методов.
В остальном всё основано на том, что в методе getDelayed реализация токена cas есть, его я и использую, чтобы заткнуть эту дыру в функциональности. Работает всё так же как в ПХП 5.6, за исключением того, что в методе getMulti нет реализации последнего параметра — флага, вместо этого всё работает так, как будто он установлен, это ничему не мешает.
:)
Комментарий для ninjacolumbo@ya.ru:
Оу :) Поправлю :)
Нашёлся более прямой способ:
http://developer.procurios.com/post/2016/05/17/Using-Memcached-with-PHP-7
Комментарий для Евгения Степанищева:
Тогда уж в догонку и «Мемекешд» :)
«Мемекешд» )) Поправил.
Тогда уж может и в посте более прямой способ упомянуть?
Комментарий для dinoel:
Напишу код попозже. Я вообще зарёкся писать про программирование, но вот, нарушился.
Комментарий для dinoel:
Написал: http://bolknote.ru/all/4497