Skip to content

POSIX 函数

概述

PHP 的 POSIX 扩展提供了访问 POSIX(可移植操作系统接口)标准的函数,主要用于获取进程信息、用户/组管理和文件权限操作。POSIX 扩展仅在 Unix/Linux 系统上可用。

适用场景

  • 获取进程/用户信息
  • 守护进程开发
  • 权限管理
  • 用户/组操作

基础概念

核心函数

函数功能返回值
posix_getpid()获取当前进程 IDint
posix_getppid()获取父进程 IDint
posix_getuid()获取当前用户 UIDint
posix_getgid()获取当前组 GIDint
posix_getpwuid()获取用户信息array|false
posix_getgrgid()获取组信息array|false
posix_getpwnam()按用户名获取信息array|false
posix_getgrnam()按组名获取信息array|false
posix_kill()发送信号给进程bool
posix_setsid()创建新会话int
posix_getlogin()获取当前登录名string|false
posix_uname()获取系统信息array|false

平台限制

POSIX 扩展仅在 Unix/Linux/macOS 上可用,不支持 Windows。

语法与代码示例

进程信息

php
<?php

echo "进程 ID: " . posix_getpid() . PHP_EOL;
echo "父进程 ID: " . posix_getppid() . PHP_EOL;
echo "当前用户 UID: " . posix_getuid() . PHP_EOL;
echo "当前组 GID: " . posix_getgid() . PHP_EOL;

// 系统信息
$uname = posix_uname();
print_r($uname);
/*
[
    'sysname' => 'Linux',
    'nodename' => 'server01',
    'release' => '5.15.0',
    'version' => '#1 SMP',
    'machine' => 'x86_64',
]
*/

// 当前登录名
$login = posix_getlogin();
echo "当前登录用户: {$login}\n";

用户/组管理

php
<?php

// 按 UID 获取用户信息
$userInfo = posix_getpwuid(1000);
print_r($userInfo);
/*
[
    'name'    => 'alice',
    'passwd'  => 'x',
    'uid'     => 1000,
    'gid'     => 1000,
    'gecos'   => 'Alice,,',
    'dir'     => '/home/alice',
    'shell'   => '/bin/bash',
]
*/

// 按用户名获取
$userInfo = posix_getpwnam('www-data');
echo "www-data UID: {$userInfo['uid']}\n";
echo "www-data Home: {$userInfo['dir']}\n";

// 按 GID 获取组信息
$groupInfo = posix_getgrgid(33);
print_r($groupInfo);
/*
[
    'name' => 'www-data',
    'passwd' => 'x',
    'members' => ['alice', 'bob'],
    'gid' => 33,
]
*/

// 按组名获取
$groupInfo = posix_getgrnam('www-data');
echo "www-data GID: {$groupInfo['gid']}\n";
echo "成员: " . implode(', ', $groupInfo['members']) . "\n";

posix_kill 发送信号

php
<?php

// 向进程发送信号
$pid = 12345;

// SIGTERM (15) - 优雅终止
posix_kill($pid, SIGTERM);

// SIGUSR1 (10) - 自定义信号
posix_kill($pid, SIGUSR1);

// 检查进程是否存在
if (!posix_kill($pid, 0)) {
    echo "进程 {$pid} 不存在\n";
} else {
    echo "进程 {$pid} 正在运行\n";
}

posix_setsid 创建会话

php
<?php

// setsid 创建新会话和新进程组
// 常用于守护进程
$sid = posix_setsid();
echo "新会话 ID: {$sid}\n";

// 配合 fork 使用
$pid = pcntl_fork();
if ($pid === 0) {
    // 子进程
    $sid = posix_setsid();
    // 现在是一个新的会话领导者
}

实战示例

守护进程管理

php
<?php

declare(strict_types=1);

class DaemonProcess
{
    private string $pidFile;
    private string $name;

    public function __construct(string $name, string $pidDir = '/var/run')
    {
        $this->name = $name;
        $this->pidFile = $pidDir . '/' . $name . '.pid';
    }

    public function daemonize(): void
    {
        // 第一次 fork
        $pid = pcntl_fork();
        if ($pid < 0) throw new RuntimeException("Fork failed");
        if ($pid > 0) exit(0);

        // 创建新会话
        posix_setsid();

        // 第二次 fork
        $pid = pcntl_fork();
        if ($pid < 0) throw new RuntimeException("Second fork failed");
        if ($pid > 0) exit(0);

        // 切换目录
        chdir('/');

        // 重设 umask
        umask(0);

        // 关闭标准文件描述符
        fclose(STDIN);
        fclose(STDOUT);
        fclose(STDERR);

        // 写入 PID 文件
        $this->writePid(posix_getpid());

        // 注册信号处理
        pcntl_async_signals(true);
        pcntl_signal(SIGTERM, [$this, 'shutdown']);
        pcntl_signal(SIGINT, [$this, 'shutdown']);
    }

    public function writePid(int $pid): void
    {
        file_put_contents($this->pidFile, (string)$pid);
    }

    public function readPid(): ?int
    {
        if (!file_exists($this->pidFile)) return null;
        return (int)file_get_contents($this->pidFile);
    }

    public function isRunning(): bool
    {
        $pid = $this->readPid();
        if ($pid === null) return false;
        return posix_kill($pid, 0);
    }

    public function shutdown(int $signo = 0): void
    {
        @unlink($this->pidFile);
        exit(0);
    }

    public function stop(): bool
    {
        $pid = $this->readPid();
        if ($pid === null) return false;

        posix_kill($pid, SIGTERM);
        sleep(2);

        if (posix_kill($pid, 0)) {
            posix_kill($pid, SIGKILL);
        }

        return true;
    }
}

// 使用
$daemon = new DaemonProcess('myworker');
// $daemon->daemonize();
// echo "Running: " . ($daemon->isRunning() ? 'yes' : 'no') . "\n";
// $daemon->stop();

注意事项

需要正确的系统权限

php
<?php

// posix_kill() 需要对目标进程有权限
// 只能向自己或同组的进程发送信号(非 root 用户)

// posix_setsid() 需要适当的权限
// 如果当前进程已经是进程组领导者,setsid 会失败

扩展检查

php
<?php

// 检查 POSIX 扩展是否可用
if (!function_exists('posix_getpid')) {
    die("POSIX 扩展未加载。请安装: pecl install posix\n");
}

// 或通过扩展检查
if (!extension_loaded('posix')) {
    die("POSIX 扩展未加载\n");
}

最佳实践

1. 使用 PID 文件管理进程

php
<?php

class PidManager
{
    public static function write(string $file, int $pid): void
    {
        $dir = dirname($file);
        if (!is_dir($dir)) mkdir($dir, 0755, true);
        file_put_contents($file, (string)$pid);
    }

    public static function read(string $file): ?int
    {
        if (!file_exists($file)) return null;
        $pid = (int)trim(file_get_contents($file));
        return $pid > 0 ? $pid : null;
    }

    public static function isAlive(string $file): bool
    {
        $pid = self::read($file);
        return $pid !== null && posix_kill($pid, 0);
    }
}

2. 获取当前用户信息

php
<?php

function getCurrentUser(): array
{
    $uid = posix_getuid();
    $userInfo = posix_getpwuid($uid);

    return [
        'uid' => $uid,
        'username' => $userInfo['name'],
        'home' => $userInfo['dir'],
        'shell' => $userInfo['shell'],
    ];
}

进阶用法

调试与测试技巧

php
<?php
declare(strict_types=1);

// 单元测试辅助函数
function createTestResource(): mixed
{
    return match (true) {
        default => new stdClass(),
    };
}

// 调试输出函数
function debugOutput(mixed , string  = ''): void
{
     =  ? ": " : '';
     .= print_r(, true);
    fwrite(STDERR,  . "\n");
}

// 性能基准测试
function benchmark(callable , int  = 1000): float
{
     = hrtime(true);
    for ($i = 0; $i < $iterations; $i++) {
        $fn();
    }
    return (hrtime(true) - $start) / 1e9;
}

日志记录实践

php
<?php
declare(strict_types=1);

/**
 * 简易日志记录器
 */
class SimpleLogger
{
    private string $logFile;
    private string $level = 'INFO';

    public function __construct(string $logFile)
    {
        $this->logFile = $logFile;
    }

    public function info(string $message, array $context = []): void
    {
        $this->log('INFO', $message, $context);
    }

    public function warning(string $message, array $context = []): void
    {
        $this->log('WARNING', $message, $context);
    }

    public function error(string $message, array $context = []): void
    {
        $this->log('ERROR', $message, $context);
    }

    private function log(string $level, string $message, array $context): void
    {
        $timestamp = date('Y-m-d H:i:s');
        $contextStr = $context ? ' ' . json_encode($context, JSON_UNESCAPED_UNICODE) : '';
        $line = "[{$timestamp}] [{$level}] {$message}{$contextStr}\n";
        file_put_contents($this->logFile, $line, FILE_APPEND | LOCK_EX);
    }
}

配置与环境检测

php
<?php
declare(strict_types=1);

// 环境检测工具
class EnvironmentChecker
{
    public static function checkRequirements(array $requirements): array
    {
        $results = [];
        foreach ($requirements as $name => $check) {
            $results[$name] = is_callable($check) ? $check() : false;
        }
        return $results;
    }

    public static function getSystemInfo(): array
    {
        return [
            'php_version' => PHP_VERSION,
            'os' => PHP_OS,
            'sapi' => PHP_SAPI,
            'memory_limit' => ini_get('memory_limit'),
            'max_execution_time' => ini_get('max_execution_time'),
            'loaded_extensions' => get_loaded_extensions(),
        ];
    }
}

常见问题排查

问题可能原因解决方案
连接超时网络问题/配置错误检查配置,增加超时时间
权限不足文件/目录权限使用 chmod/chown 修正
性能下降索引缺失/数据量大添加索引,优化查询
数据不一致并发冲突/事务残留使用锁机制和事务
内存溢出大数据集/未释放资源增大内存限制,分批处理

故障排除步骤

  1. 检查错误日志和异常信息
  2. 确认配置和环境是否正确
  3. 使用调试工具逐步排查
  4. 参考官方文档查找已知问题

版本兼容性说明

功能最低版本说明
基础功能PHP 8.1本文档基准版本
只读属性PHP 8.1public readonly 修饰符
枚举类型PHP 8.1enum 类型和 match 表达式
FiberPHP 8.1协程/轻量级并发
命名参数PHP 8.0foo(arg_name: value)
联合类型PHP 8.0`int
Null 安全运算符PHP 8.0$obj?->method()
析构器 promotionPHP 8.0__construct(public $x)
php
<?php
declare(strict_types=1);

// 版本兼容性检测
function ensureVersion(string $minVersion): void
{
    if (version_compare(PHP_VERSION, $minVersion, '<')) {
        throw new RuntimeException(
            sprintf('需要 PHP %s+, 当前版本: %s', $minVersion, PHP_VERSION)
        );
    }
}

ensureVersion('8.1.0');

参考链接