Методы обмена данными между PHP-процессами: от разделяемой памяти до файлового кэша

Раздел: Разработка на PHP -> Функции обмена данными PHP

Основные способы обмена данными в PHP

Как организовать быстрый обмен переменными между разными скриптами PHP на одном сервере?

Наиболее эффективное решение – использование разделяемой памяти System V через функции shm_attach, shm_put_var, shm_get_var. Данные хранятся в оперативной памяти и доступны всем процессам, знающим общий ключ.


<?php
// Скрипт 1: запись
$key = ftok(__FILE__, 't');
$shm = shm_attach($key, 1024, 0777); // размер 1KB
$data = ['user' => 'admin', 'time' => time()];
shm_put_var($shm, 1, $data);
echo "Данные записаны";
shm_detach($shm);
?>
  

Share php (функция share в php)


<?php
// Скрипт 2: чтение
$key = ftok(__FILE__, 't'); // тот же файл для ftok
$shm = shm_attach($key, 1024, 0777);
if (shm_has_var($shm, 1)) {
    $data = shm_get_var($shm, 1);
    print_r($data);
} else {
    echo "Данных нет";
}
shm_detach($shm);
?>
  

Типичные ошибки:

  • Несовпадение ключа – используйте ftok с одинаковым файлом.
  • Переполнение выделенной памяти – увеличьте второй аргумент shm_attach.
  • Права доступа – укажите 0777, чтобы другие процессы могли читать/писать.
  • Отсутствие расширения sysvshm – проверьте phpinfo().

Цель: высокая скорость, данные в RAM, подходит для флагов, счетчиков, конфигураций.

Как реализовать обмен данными без установки дополнительных расширений?

Используйте файловую систему с блокировками. Данные сериализуются и сохраняются в общий файл.


<?php
$file = '/tmp/shared.dat';
$data = ['views' => 10];
$fp = fopen($file, 'c+');
if (flock($fp, LOCK_EX)) {
    ftruncate($fp, 0);
    fwrite($fp, serialize($data));
    flock($fp, LOCK_UN);
}
fclose($fp);
?>
  

Проблемы:

  • Медленнее памяти, особенно при высоких нагрузках.
  • Риск повреждения данных при аварийном завершении.
  • Необходимость синхронизации через flock.

Цель: простой способ для небольших проектов без прав на установку расширений.

Как использовать APCu для обмена данными между запросами?

APCu (APC User Cache) хранит данные в разделяемой памяти, но доступен только в рамках одного сервера.


<?php
// Запись
apcu_store('my_var', ['value' => 123], 3600);
// Чтение
$val = apcu_fetch('my_var');
if (apcu_exists('my_var')) {
    echo $val['value'];
}
?>
  

Ошибки:

  • APCu не установлен – требуется расширение apcu.
  • Данные хранятся только в памяти одного сервера, не для кластеров.

Цель: кэширование и быстрый обмен между скриптами одного хоста.

Как синхронизировать доступ к ресурсу между процессами?

Семафоры System V (sem_get, sem_acquire) часто применяются вместе с разделяемой памятью.


<?php
$sem_id = sem_get(1234, 1, 0777);
sem_acquire($sem_id);
// критическая секция – работа с разделяемой памятью
$shm = shm_attach(ftok(__FILE__, 't'));
$counter = shm_get_var($shm, 1);
$counter++;
shm_put_var($shm, 1, $counter);
shm_detach($shm);
sem_release($sem_id);
?>
  

Ошибки:

  • Забыли освободить семафор – возникает deadlock.
  • Семафор не удалён после завершения – накапливаются.

Цель: атомарные операции с общими данными.

Расширенные примеры с пояснениями

Пример 1: Разделяемая память с несколькими переменными

Пример

<?php
$key = ftok('/tmp/test.php', 'R');
$shm = shm_attach($key, 4096);

// Запись разных типов данных
shm_put_var($shm, 1, 'строка');
shm_put_var($shm, 2, 12345);
shm_put_var($shm, 3, ['a' => 1, 'b' => 2]);

echo "Данные сохранены.";
shm_detach($shm);
?>
Данные сохранены.

Пример 2: Чтение и проверка существования переменной

Пример

<?php
$key = ftok('/tmp/test.php', 'R');
$shm = shm_attach($key, 4096);

if (shm_has_var($shm, 1)) {
    $str = shm_get_var($shm, 1);
    echo "Переменная 1: $str\n";
} else {
    echo "Переменной 1 нет.\n";
}

if (shm_has_var($shm, 3)) {
    $arr = shm_get_var($shm, 3);
    print_r($arr);
}

shm_detach($shm);
?>
Переменная 1: строка
Array
(
    [a] => 1
    [b] => 2
)

Пример 3: Сброс и удаление разделяемой памяти

Пример

<?php
$key = ftok('/tmp/test.php', 'R');
$shm = shm_attach($key, 4096);

// Удаление одной переменной
shm_remove_var($shm, 2);
echo "Переменная 2 удалена.\n";

// Полный сброс сегмента
shm_remove($shm);
echo "Сегмент разделяемой памяти удалён.\n";
?>
Переменная 2 удалена.
Сегмент разделяемой памяти удалён.

Пример 4: Файловый обмен с использованием JSON

Пример

<?php
$file = '/tmp/data.json';

// Запись
$data = ['login' => 'user1', 'ip' => '192.168.0.1'];
$wrapper = fopen($file, 'c+');
flock($wrapper, LOCK_EX);
ftruncate($wrapper, 0);
fwrite($wrapper, json_encode($data));
fflush($wrapper);
flock($wrapper, LOCK_UN);
fclose($wrapper);
echo "Запись завершена.\n";

// Чтение
$content = file_get_contents($file);
$parsed = json_decode($content, true);
print_r($parsed);
?>
Запись завершена.
Array
(
    [login] => user1
    [ip] => 192.168.0.1
)

Пример 5: Использование APCu для подсчёта просмотров

Пример

<?php
$key = 'page_views';
if (!apcu_exists($key)) {
    apcu_store($key, 0);
}
apcu_inc($key);
echo "Просмотров: " . apcu_fetch($key);
?>
Просмотров: 3

Нестандартный пример: Обмен через сокеты Unix Domain

Пример

<?php
// Сервер (скрипт 1)
$socket = socket_create(AF_UNIX, SOCK_STREAM, 0);
$path = '/tmp/shared_socket';
@unlink($path);
socket_bind($socket, $path);
socket_listen($socket);
$client = socket_accept($socket);
$msg = "Hello from server";
socket_write($client, $msg, strlen($msg));
socket_close($client);
socket_close($socket);
?>
Пример

<?php
// Клиент (скрипт 2)
$socket = socket_create(AF_UNIX, SOCK_STREAM, 0);
socket_connect($socket, '/tmp/shared_socket');
$response = socket_read($socket, 1024);
echo $response;
socket_close($socket);
?>
Hello from server

Функция share в PHP - comments

En
Share php (php)