我目前正在使用以下散列resource
的方法进行查找:
$foo = socket_create(...);
$bar = socket_create(...);
$map[(int)$foo] = 'foo';
$map[(int)$bar] = 'bar';
echo $map[(int)$foo]; // "foo"
integer
为此投出最佳选择吗?如果没有,那么其他什么样的散列方法会更好或更有效?这些查找将在紧密循环(套接字轮询)中以每秒数百次的速度执行,因此我已经排除了基于迭代的解决方案。
修改
为了更好地解释我的情况,socket_select()
函数通过引用获取套接字资源数组并修改它们,以便在函数调用之后,它们将仅包含已更改的资源(例如,准备好读取从)。我使用Socket
类作为套接字资源的包装器,使我的代码更抽象和可测试:
$socketObject = new Socket($socketResource);
我的另一个类保留了每次调用socket_select()
时需要轮询的所有套接字资源的列表:
$reads = [$socketResource1, $socketResource2, ...];
socket_select($reads, null, null, 0);
在调用socket_select()
之后,我知道哪个socket 资源已经更改,但是为了在我的代码中执行任何有意义的操作,我需要知道哪个socket 对象那些资源对应。因此,我需要一些方法将套接字资源映射到它们的对象:
foreach ($reads as $socketResource) {
// Which socket object does $socketResource correspond to here?
// Currently, I use a solution like this:
$socketObject = $this->map[(int)$socketResource];
// Unfortunately, this behavior isn't guaranteed, so it isn't reliable...
}
答案 0 :(得分:6)
未定义casting resources to integer时观察到的行为(请参阅页面底部的警告说明)。所以,即使这个works now and reliably did for a long time,你也必须意识到没有什么可以依靠,如果没有通知就不能改变。
澄清后编辑:
不使用资源作为密钥,而是使用两个数组。将Socket对象的哈希映射到实际对象。另一个将相同的哈希映射到资源。然后将后一个数组传递给socket_select
。在函数不会更改数组键的前提下,您可以迭代数组并使用键在O(1)中查找Socket:
$r1 = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
$r2 = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
$s1 = new Socket($foo);
$s2 = new Socket($bar);
$socketMap = array(
spl_object_hash($s1) => $s1,
spl_object_hash($s2) => $s2
);
$reads = array(
spl_object_hash($s1) => $r1,
spl_object_hash($s2) => $r2
);
socket_select($reads, null, null, 0);
foreach (array_keys($reads) as $hash) {
$socketObject = $socketMap[$hash];
}
更新:不再定义将资源转换为整数,如链接的手册页中所示。如果资源转换为整数,则结果将是PHP在运行时分配给资源的唯一资源编号。
答案 1 :(得分:1)
我将此函数与multi_curl一起使用,对排序非常有效,以确保文本不会随机排列:
function get_resource_id($resource) {
if (!is_resource($resource))
return false;
return array_pop(explode('#', (string)$resource));
}
答案 2 :(得分:0)
我建议你制作一个集合对象,而不是$map
变量,例如。
class ResourceCollection implements ArrayAccess {
private $map = array();
/**
* returns index of element or FALSE if not existent
*/
protected function getIndex($offset){
if(is_resource($offset)){
$index = array_search($offset, $this->map);
}
else // you can add more tests if you need
if(isset($this->map[$offset]))
$index = $offset;
else
$index = false;
return $index;
}
/**
* required by ArrayAccess interface
*/
public function offsetExists($offset){
return ($this->getIndex($offset) === false)? false : true;
}
/**
* required by ArrayAccess interface
*/
public function offsetGet($offset){
$index = $this->getIndex($offset);
if($index === false)
throw new ... // or handle error of non-existent element
return $this->map[$index];
}
// etc., implement ArrayAccess interface, Iterator and anything you want
}
虽然我没有对它进行测试,但是这应该允许你像访问数组那样访问对象,我希望这种方式(没有这方面的文档)资源可以用作数组索引。
答案 3 :(得分:0)
我知道这个问题很老,但截至今天,您还可以使用 linked-hash-map 并将资源用作数组键。
您可以使用 Composer 安装它:
composer require tonix-tuft/linked-hash-map
像这样使用它:
<?php
// ...
use LinkedHashMap\LinkedHashMap;
$map = new LinkedHashMap();
$foo = socket_create(...);
$bar = socket_create(...);
$map[$foo] = 'foo';
$map[$bar] = 'bar';
echo $map[$foo]; // "foo"