2024 年 PHP 大会日本站

shm_put_var

(PHP 4, PHP 5, PHP 7, PHP 8)

shm_put_var在共享内存中插入或更新变量

描述

shm_put_var(SysvSharedMemory $shm, int $key, mixed $value): bool

shm_put_var() 使用给定的 key 插入或更新 value

如果 shm 不是有效的 SysV 共享内存索引,或者剩余的共享内存不足以完成请求,则会发出警告(E_WARNING 等级)。

参数

shm

shm_attach() 获取的共享内存段。

key

变量键。

value

变量。所有变量类型 serialize() 支持,通常这意味着除资源和某些无法序列化的内部对象之外的所有类型。

返回值

成功返回 true,失败返回 false

变更日志

版本 描述
8.0.0 shm 现在期望一个 SysvSharedMemory 实例;以前,期望一个 resource

参见

添加注释

用户贡献的注释 8 条注释

Hendrik Klindworth
15 年前
shm_put_var 没有防止竞争条件的保护。如果两个脚本同时插入相同的键,php 可能会出现段错误。
jasonrlester at yahoo dot com
16 年前
很遗憾,troy是对的。

以下脚本将返回

resource(5) of type (stream)
int(0)

<?php

define
("FOPEN_RESOURCE", 1);
define("FOPEN_FILEPATH", "/path/to/file");

$fopen_resource = fopen(FOPEN_FILEPATH, "w");

var_dump($fopen_resource);

$shm_id = shm_attach(1);
if (
$shm_id === false)
{
echo
"Fail to attach shared memory.\n";
}

if (!
shm_put_var($shm_id, FOPEN_RESOURCE, $fopen_resource))
{
echo
"Failed to put var 1 in shared memory $shm_id.\n";
}

$sm_fopen_resource = shm_get_var($shm_id, FOPEN_RESOURCE);
if (
$sm_fopen_resource === false)
{
echo
"Failed to retreive fopen_resource from Shared memory\r\n";
}

var_dump($sm_fopen_resource);

if(
$shm_id) shm_remove($shm_id);
if(
$fopen_resource) fclose($fopen_resource);

?>
troy
16 年前
这并不完全准确。并非所有变量类型都受支持,您不能将资源变量放入共享内存。

当您尝试取出它时,它将为零。
ygbr at me dot com
15 年前
它会支持像 pfsockopen() 指针这样的资源标识符吗?

主要问题是,当我们将 PHP 作为 Apache 模块运行时,我们永远不知道下一个请求将绑定到哪个进程,这使得不可能拥有真正的持久套接字连接,除非我们可以将指向它的指针存储起来,或者直接使用 fopen() 之类的函数打开套接字 inode 并再次检索相同的资源指针。

我以为我可以使用 shm,但似乎 shm 不允许存储资源指针……太可惜了……:(
cong818 at gmail dot com
11 年前
在我看来,shm_put_var() 与整数键 0 配合得不好。我将其更改为 1,它运行良好。
orwellophile at spamtrak dot org
14 年前
引用:“它会支持像 pfsockopen() 指针这样的资源标识符吗……我们使用 Apache 模块运行 PHP……没有办法拥有真正的持久套接字”

对不起,但这对我来说没有意义……如果您想恢复套接字,只需使用相同的 host 和 port 调用 pfsockopen() - 您将获得相同的套接字。无需传递实际的资源变量。

如果每个套接字都有一些惊人地特殊和独特的特性,您可以执行以下操作 - 这应该适用于任何持久资源

为了区分或获取特定的资源 - 只需序列化/存储每个资源唯一 ID 的索引,以及使该资源唯一的细节。

您可以像这样获得一个唯一的资源标识符作为整数值

<?php
$rid
= str_replace("Resource id #", "", print_r($fp, true));
// $rid = 2
?>

由于 pfsockopen() 使用主机名和端口作为恢复持久连接的唯一键,您可以添加 DNS 通配符或在 /etc/hosts(或 windows 等效项)中添加多个手动条目,如下所示

resource-0.host.com 192.168.100.1
resource-1.host.com 192.168.100.1
resource-2.host.com 192.168.100.1
resource-3.host.com 192.168.100.1

然后,在查阅您序列化后的资源列表后,您可以使用其资源 ID 连接到特定资源。

例如:`$pf = pfsockopen("resource-$rid.host.com", $port, $timeout);`

新资源在各个方面都将与原始资源相同。

对于基于文件的流资源,您可以使用符号链接执行类似的操作,或者使用下一种方法……

对于基于 URL 的资源或其他具有“路径”的资源(我不知道是否存在涉及此类事物的持久性函数),您可以使用路径中的额外信息来区分它们。例如

http://host.com/resource-4/../script.php
http://[email protected]/script.php
/tmp/././././file.txt

在第一个示例中,多余的“resource-4”将被 web 服务器忽略。

在第二个示例中,多余的用户名将被 web 服务器忽略。(对于 `mysql_pconnect`,可以使用多个用户名执行类似的操作)。

在第三个示例中,四个连续出现的“无效”字符串“./”将表示资源#4。

如果这还不够,您可以使用 PHP 共享内存资源本身与它们的 .c 对应部分创建的资源互操作的事实。这允许您编写一个精简的 .c 应用程序来处理繁重的工作。

或者,您可以尝试使用持久性流和上述方法重新连接到您自己的 web 服务器,以达到最终结果。我想不出任何需要如此极端方法的例子,但我相信这并非不可能。

我个人使用一个 117 MB 的二进制数据库,该数据库存储在共享内存中,既可从命令行(使用编译的 .c 应用程序)访问,也可从 web(通过 PHP 和 `ftok()`/`shmop_open()`/`shmop_read()`)访问。
Jason Lester
11 年前
是的,可以使用共享内存保持真正的资源持久性级别。PHP 中的所有变量都作为 zval 存储在公共哈希表中,包括资源标识符。只要整个 PHP 进程没有关闭,就有可用的哈希表可以超出请求的生存期。您只需要将标识符存储在此类哈希表中并找到跟踪它们的方法,您就可以接收原始资源。

我不知道为什么 PHP 没有提供设置/获取持久性资源的方法,但这可能是由于它提供了许多类型的 SAPI,并且并非所有 SAPI 都能实现此功能,包括仍然远未过时的 CGI。

另一个问题是,在用户空间中拥有这样的访问权限必然会导致多个 PHP 进程尝试访问同一资源的问题。从这个角度来看,如果没有更好的同步机制,实际上没有安全的方法来安全地使用这样的 getter/setter。
tomlove at gmail dot com
20 年前
尽可能少用变量键。对于大型数据数组,最好使数组多维并在一个变量键下存储,而不是使用变量键作为索引。当需要反复从数组末尾获取数据并且更新频率较低时,这种好处尤其明显。
To Top