PHP для системного программирования: взлом стереотипов
Когда мы слышим "системное программирование", в голову сразу приходят C, Rust или Go. PHP? Серьезно? Абсолютно. Большинство разработчиков даже не подозревают, что PHP — это не только про веб-формы и WordPress. Это полноценный язык, способный управлять процессами, работать с сокетами, создавать демоны и взаимодействовать с ядром операционной системы. В этой статье мы разберем, как PHP может стать вашим инструментом для системного программирования, и покажем реальные примеры кода.
Почему это вообще нужно? Представьте: вам нужно написать утилиту для мониторинга сервера, обработчик логов в реальном времени или простой планировщик задач. Вы знаете PHP, и переучиваться на C для простой задачи — оверкилл. PHP для системного программирования позволяет решать такие задачи быстро и без боли. Давайте копать глубже.
Что такое системное программирование на PHP?
Системное программирование — это разработка программ, которые взаимодействуют с аппаратурой и операционной системой на низком уровне. В PHP это возможно благодаря расширениям pcntl, posix, sockets и встроенным функциям работы с файлами и процессами. PHP не предназначен для написания драйверов, но для создания системных утилит, демонов и скриптов автоматизации он подходит отлично.
Ключевые возможности PHP для системного программирования
- Управление процессами — создание, завершение, ожидание (pcntl_fork, pcntl_wait).
- Сигналы — обработка SIGTERM, SIGHUP и других (pcntl_signal).
- Права доступа — работа с UID, GID, масками (posix_getuid, posix_setuid).
- Сокеты — создание серверов и клиентов (socket_create, socket_bind).
- Файловая система — inode, жесткие ссылки, мониторинг изменений (inotify).
- Параллельное выполнение — многопроцессность, потоки (pthreads, параллельные процессы).
Все эти возможности доступны "из коробки" или через стандартные расширения. Никаких сторонних библиотек не нужно.
Пример 1: Демон-мониторинг на PHP
Напишем простой демон, который каждые 10 секунд проверяет, запущен ли процесс nginx, и пишет лог. Это классическая задача системного программирования.
<?php
// Демон для мониторинга nginx
declare(ticks = 1);
// Стартуем как демон
function daemonize() {
$pid = pcntl_fork();
if ($pid == -1) {
die("Ошибка форка\n");
} elseif ($pid) {
// Родительский процесс завершаем
exit(0);
}
// Дочерний процесс — новый сеанс
posix_setsid();
}
daemonize();
// Обработка сигналов
pcntl_signal(SIGTERM, function($signo) {
file_put_contents('/var/log/monitor.log', "Получен SIGTERM, завершаюсь\n", FILE_APPEND);
exit(0);
});
// Основной цикл
while (true) {
// Проверяем nginx через shell_exec
$output = shell_exec('pgrep nginx | wc -l');
$count = trim($output);
$log = "[" . date('Y-m-d H:i:s') . "] Процессов nginx: " . $count . "\n";
file_put_contents('/var/log/monitor.log', $log, FILE_APPEND);
sleep(10);
}
?>
Этот код демонстрирует PHP для системного программирования в действии: форк процесса, создание демона, обработка сигналов и работа с системными утилитами. Запускаем скрипт в фоне — и он работает как настоящий сервис.
Пример 2: Параллельная обработка данных с помощью форков
Представьте, что нужно обработать 1000 файлов логов. Последовательная обработка займет часы. Используем многопроцессность на PHP.
<?php
$files = glob('/var/log/*.log');
$maxWorkers = 4;
$workers = [];
foreach ($files as $file) {
// Если достигли лимита воркеров — ждем завершения
while (count($workers) >= $maxWorkers) {
$pid = pcntl_wait($status, WNOHANG);
if ($pid > 0) {
unset($workers[$pid]);
} else {
usleep(100000); // 100ms
}
}
$pid = pcntl_fork();
if ($pid == -1) {
die("Ошибка форка");
} elseif ($pid) {
// Родитель: запоминаем дочерний PID
$workers[$pid] = $file;
} else {
// Дочерний процесс: обрабатываем файл
$content = file_get_contents($file);
$lines = substr_count($content, "ERROR");
file_put_contents('/tmp/results.txt', "$file: $lines ошибок\n", FILE_APPEND);
exit(0);
}
}
// Ждем завершения всех воркеров
while (count($workers) > 0) {
$pid = pcntl_wait($status);
if ($pid > 0) {
unset($workers[$pid]);
}
}
echo "Обработка завершена\n";
?>
Здесь PHP для системного программирования раскрывается через параллельную обработку: мы создаем дочерние процессы, каждый из которых работает независимо. Это реальный способ ускорить batch-задачи без сложных очередей.
Пример 3: Сетевой сервер на сокетах
Напишем простой TCP-сервер, который принимает команды и выполняет их. Это основа для создания собственных сервисов.
<?php
$host = '127.0.0.1';
$port = 9000;
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false) {
die("Ошибка создания сокета: " . socket_strerror(socket_last_error()) . "\n");
}
if (socket_bind($socket, $host, $port) === false) {
die("Ошибка привязки: " . socket_strerror(socket_last_error($socket)) . "\n");
}
if (socket_listen($socket, 5) === false) {
die("Ошибка прослушивания: " . socket_strerror(socket_last_error($socket)) . "\n");
}
echo "Сервер запущен на $host:$port\n";
while (true) {
$client = socket_accept($socket);
if ($client === false) {
echo "Ошибка принятия соединения\n";
continue;
}
$input = socket_read($client, 1024);
$command = trim($input);
// Выполняем команду (осторожно, безопасность!)
$output = shell_exec($command . ' 2>&1');
if ($output === null) {
$output = "Команда не выполнена\n";
}
socket_write($client, $output, strlen($output));
socket_close($client);
}
socket_close($socket);
?>
Этот пример показывает PHP для системного программирования в сетевом контексте. Такой сервер можно использовать для удаленного управления или отладки.