phpenv中shmop扩展默认不启用,须进入对应php源码ext/shmop目录,用phpize、configure、make install编译安装,并在php.ini中添加扩展路径;key需硬编码或稳定哈希避免冲突;写入前须校验size;段需显式shmop_delete释放,否则常驻内核。

phpEnv 里 shmop 扩展默认不启用,必须手动编译安装
phpEnv 是基于源码编译的 PHP 环境管理工具,它不会自动启用 shmop 扩展——哪怕你用的是 PHP 7.4+ 或 8.x。这是因为 shmop 在 PHP 源码中属于“可选扩展”,phpEnv 构建时默认跳过它。
你不能靠改 php.ini 加 extension=shmop.so 就生效;文件根本不存在。必须进对应 PHP 版本源码的 ext/shmop/ 目录,走完整编译流程:
- 先用
phpenv version-name确认当前激活版本(如7.4.33),再进~/.phpenv/versions/7.4.33/src/ext/shmop/ - 运行
phpize(确保该 PHP 版本的phpize在 PATH 中,可用phpenv which phpize验证) - 执行
./configure --with-php-config=~/.phpenv/versions/7.4.33/bin/php-config -
make && make install,成功后会输出Installing shared extensions: .../shmop.so - 在
~/.phpenv/versions/7.4.33/etc/php.ini末尾加一行:extension=/path/to/shmop.so(路径以make install输出为准) - 重启 CLI 或 Web 服务(如果是 php-fpm,执行
phpenv fpm-restart)
key 必须是 int,ftok(__FILE__, 'x') 在 phpEnv 多项目下极易冲突
很多示例用 ftok(__FILE__, 't') 生成 key,但在 phpEnv 环境中,多个项目共用同一套 PHP 二进制、且可能部署在相同路径(如都软链到 /var/www/project),__FILE__ 值高度重复,ftok 输出的 key 极大概率撞车——轻则 shmop_open 失败,重则读到其他项目的脏数据。
更稳妥的做法是硬编码或稳定哈希:
- 直接用整数 key:
$key = 0x12345678;(确保十六进制转十进制后仍是合法 int) - 用项目标识做哈希:
$key = hexdec(substr(md5('my-project-name'), 0, 8)); - 避免用字母、字符串、时间戳等不可控输入参与 key 生成
shmop_write 不扩容、不截断、不补零,写前必须校验 size
shmop_write($shmop, $data, $offset) 不是“追加”操作,它严格受限于 shmop_open 创建时指定的 $size。常见错误包括:
- 写入长度超过
$size→ 返回false,无警告 - 写入长度小于
$size→ 剩余内存保留上次写入的旧字节(不是 \0),下次shmop_read会读出垃圾数据 - 没调
shmop_size($shmop)就直接写 → 若段被别人重建过大小,你的偏移计算就全错
安全写法示例:
$size = shmop_size($shmop);
if (strlen($data) > $size) {
throw new RuntimeException("data too long for shm segment");
}
// 写入前清空整块(可选,视业务需要)
shmop_write($shmop, str_pad($data, $size, "\0"), 0);
共享内存不会随进程退出消失,不删就会一直占系统资源
这是最容易被忽略的一点:只要没调 shmop_delete(),共享内存段就永远留在内核里,哪怕所有 PHP 进程都结束了。phpEnv 下调试频繁启停,很容易堆积大量僵尸段。
检查和清理方法:
- 终端执行
ipcs -m查看所有共享内存段(注意列中的key和nattch,后者为 0 表示无进程连接) - 确认某段无用后,用
ipcrm -M 0x12345678(key 十六进制)或ipcrm -m 1948581891(shmid 十进制)删除 - 代码中应在明确不再需要时调
shmop_delete($shmop),而不是只靠shmop_close()
尤其注意:Web 场景下,不能把 shmop_delete() 放在脚本末尾——请求结束不等于进程结束(PHP-FPM worker 会复用),删早了别的请求就打不开段了。真正安全的删除时机,是业务逻辑确认“全局不再需要”时,比如配置热更新完成后的清理钩子。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











