PHP脚本如何变成服务

wen PHP项目 4

本文目录导读:

PHP脚本如何变成服务

  1. 使用 PHP 内置的异步框架
  2. 使用 systemd 服务(传统PHP + Nginx/Apache)
  3. 使用 Supervisor 管理
  4. 编写守护进程脚本(纯PHP)
  5. 使用 Docker 容器化
  6. 使用 PHP 内置服务器 + 进程管理
  7. 使用 ReactPHP 事件循环
  8. 生产环境部署建议
  9. 选择建议
  10. 注意事项

将PHP脚本变成服务(常驻内存运行)有几种常见方案,我会按推荐程度从高到低介绍:

使用 PHP 内置的异步框架

Swoole(最推荐)

// server.php
<?php
use Swoole\Http\Server;
use Swoole\Http\Request;
use Swoole\Http\Response;
$server = new Server("0.0.0.0", 9501);
$server->on("start", function(Server $server) {
    echo "Swoole HTTP server started\n";
});
$server->on("request", function(Request $request, Response $response) {
    $response->header("Content-Type", "text/plain");
    $response->end("Hello from Swoole!\n");
});
$server->start();

运行:

php server.php

Workerman

<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker("websocket://0.0.0.0:2346");
$worker->onMessage = function(TcpConnection $connection, $data) {
    $connection->send("Hello: $data\n");
};
Worker::runAll();

运行:

php worker.php start

使用 systemd 服务(传统PHP + Nginx/Apache)

# /etc/systemd/system/php-app.service
[Unit]
Description=PHP Application Service
After=network.target
[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/var/www/myapp
ExecStart=/usr/bin/php -S 0.0.0.0:8080 -t /var/www/myapp
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target

启用服务:

# 启动服务
sudo systemctl enable php-app
sudo systemctl start php-app
# 查看状态
sudo systemctl status php-app

使用 Supervisor 管理

# /etc/supervisor/conf.d/php-app.conf
[program:php-app]
command=/usr/bin/php /path/to/your/script.php
directory=/path/to/app
autostart=true
autorestart=true
startretries=3
stderr_logfile=/var/log/php-app.err.log
stdout_logfile=/var/log/php-app.out.log
user=www-data

编写守护进程脚本(纯PHP)

<?php
// daemon.php
class Daemon {
    private $pidfile;
    private $logfile;
    public function __construct($pidfile, $logfile) {
        $this->pidfile = $pidfile;
        $this->logfile = $logfile;
    }
    public function start() {
        if ($this->isRunning()) {
            echo "Already running\n";
            return;
        }
        $pid = pcntl_fork();
        if ($pid == -1) {
            die("Could not fork\n");
        } elseif ($pid) {
            // Parent process
            exit;
        } else {
            // Child process
            posix_setsid();
            $this->run();
        }
    }
    private function run() {
        // 主循环
        while (true) {
            $this->log("Working...");
            sleep(5);
        }
    }
    private function isRunning() {
        if (file_exists($this->pidfile)) {
            $pid = file_get_contents($this->pidfile);
            if (posix_kill($pid, 0)) {
                return true;
            }
        }
        return false;
    }
    private function log($message) {
        file_put_contents($this->logfile, 
            date('Y-m-d H:i:s') . " - $message\n", FILE_APPEND);
    }
}
$daemon = new Daemon('/tmp/myapp.pid', '/var/log/myapp.log');
$daemon->start();

使用 Docker 容器化

# Dockerfile
FROM php:8.2-cli
WORKDIR /app
COPY . /app
RUN docker-php-ext-install pcntl
CMD ["php", "server.php"]
# docker-compose.yml
version: '3'
services:
  php-app:
    build: .
    ports:
      - "9501:9501"
    restart: always

使用 PHP 内置服务器 + 进程管理

# 使用 nohup 后台运行
nohup php -S 0.0.0.0:8080 > /var/log/php-server.log 2>&1 &
# 或者使用 timeout 并配合 crontab 自动重启

使用 ReactPHP 事件循环

<?php
require_once __DIR__ . '/vendor/autoload.php';
use React\EventLoop\Factory;
use React\Http\Server;
use Psr\Http\Message\ServerRequestInterface;
use React\Http\Message\Response;
$loop = Factory::create();
$server = new Server($loop, function (ServerRequestInterface $request) {
    return new Response(
        200,
        ['Content-Type' => 'text/plain'],
        "Hello World!\n"
    );
});
$socket = new React\Socket\Server(8080, $loop);
$server->listen($socket);
echo "Server running on port 8080\n";
$loop->run();

生产环境部署建议

使用 Open Swoole 生产配置

# swoole.ini
[swoole]
swoole.display_errors = Off
swoole.enable_coroutine = On

结合 PHP-FPM + Nginx

# nginx.conf
upstream php_websocket {
    server 127.0.0.1:9501;
}
server {
    listen 80;
    location / {
        proxy_pass http://php_websocket;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
    }
}

选择建议

  • WebSocket/长连接: 使用 Swoole/Workerman
  • HTTP API: 使用 Swoole HTTP server
  • 传统应用: 使用 PHP-FPM + 进程管理
  • 简单定时任务: 使用 cron + PHP CLI
  • 微服务架构: 使用 Docker + Swoole

注意事项

  1. 内存泄漏: 长期运行要注意内存管理
  2. 错误处理: 必须有完善的错误捕获机制
  3. 日志记录: 记录运行日志便于排查问题
  4. 自动重启: 配置进程管理软件自动重启
  5. 性能监控: 监控内存和CPU使用情况

选择哪种方案取决于你的具体需求(性能要求、部署环境、维护成本等),对于现代PHP应用,推荐使用 Swoole 或 Workerman 方案,性能最好且功能最完善。

抱歉,评论功能暂时关闭!