PHP中std::set的等价物?
在PHP中,C plus加上“set”的等效函数是什么(“set是一种存储唯一元素的关联容器,元素本身就是其中的键”)?在PHP中,您可以使用它。在PHP中没有内置的与PHP中std::set的等价物?,php,c++,set,Php,C++,Set,在PHP中,C plus加上“set”的等效函数是什么(“set是一种存储唯一元素的关联容器,元素本身就是其中的键”)?在PHP中,您可以使用它。在PHP中没有内置的与std::set等效的函数 您可以使用“类似”的数组集,但规则的实施取决于您。没有规则,但它们可以 这是链接失效前的一份副本。。全部内容 PHP:arrayvs.SplObjectStorage 我的一个项目QueryPath执行许多需要维护一组唯一对象的任务。在我寻求优化QueryPath的过程中,我一直在研究各种有效存储对象集
std::set
等效的函数
您可以使用“类似”的数组集,但规则的实施取决于您。没有规则,但它们可以 这是链接失效前的一份副本。。全部内容
PHP:array
vs.SplObjectStorage
我的一个项目QueryPath执行许多需要维护一组唯一对象的任务。在我寻求优化QueryPath的过程中,我一直在研究各种有效存储对象集的方法,以提供方便的包含检查。换句话说,我需要一个数据结构,它保存一个唯一对象的列表,并且可以快速告诉我该列表中是否存在某个对象。循环浏览列表内容的能力也是必要的
最近,我将候选人名单缩小为两种方法:
使用好的老式数组来模拟散列集。
使用PHP5.2及更高版本中的SPLObjectStorage
系统。
在直接在QueryPath
中实现任何东西之前,我首先开始设计这两种方法,然后在Crell的帮助下对这两种方法运行一些微基准测试。说结果令人惊讶是轻描淡写的。基准测试可能会改变我构建未来代码的方式,无论是在Drupal
内部还是外部
设计
在介绍基准测试之前,我想快速解释一下我确定的两种设计
模拟哈希集的数组
我一直在考虑的第一种方法是使用PHP的标准数组()来模拟由哈希映射支持的集(“哈希集”)。集合是一种数据结构,用于保存唯一元素的列表。在我的例子中,我感兴趣的是存储一组唯一的DOM对象。哈希集是使用哈希表实现的集,其中键是存储值的唯一标识符。虽然人们通常会编写一个类来封装此功能,但我决定将实现作为一个裸阵列进行测试,上面没有任何间接层。换句话说,我将要介绍的是散列集实现的内部结构
目标是:存储一组(唯一的)对象,使它们(a)易于迭代,(b)检查成员资格的成本低廉。
策略:创建一个关联数组,其中键是散列ID,值是对象
有了一个相当好的散列函数,上面概述的策略应该可以正常工作
“相当好的散列函数”——这是第一个问题。如何为像DOMDocument
这样的对象生成好的哈希函数?一种(不好的)方法是序列化对象,然后,也许,获取其MD5哈希。但是,这在许多对象上都不起作用——特别是不能序列化的任何对象。例如,DOMDocument
,实际上是由资源支持的,不能序列化
不过,我们需要对这样的函数进行深入研究。事实证明,PHP5中有一个对象哈希函数。它被称为spl\u object\u hash()
,它可以获取任何对象(即使是非本机PHP的对象)并为其生成hashcode
使用spl\u object\u hash()。此结构类似于以下内容:
array(
$hashcode => $object
);
$object = new stdClass();
$hashkey = spl_object_hash($object);
// ...
// Check whether $arr has the $object.
if (isset($arr[$hashkey])) {
// Do something...
}
例如,我们生成一个如下所示的条目:
$object = new stdClass();
$hashcode = spl_object_hash($object);
$arr = array(
$hashcode => $object
);
在上面的示例中,hashcode字符串是一个数组键,而对象本身就是数组值。请注意,由于每次对对象重新哈希时哈希代码都是相同的,因此它不仅用作比较点(“如果对象a的哈希键==对象b的哈希键,那么a==b”),还用作唯一性约束。每个数组只能存在一个具有指定哈希代码的对象,因此不可能在数组中放置同一对象的两个副本(实际上是两个引用)
对于这样的数据结构,我们有许多现成的函数来操作该结构,因为我们可以使用所有PHP数组函数。所以在某种程度上,这是一个有吸引力的开箱即用的选择
至少在我们的上下文中,最重要的任务是确定集合中是否存在条目。此检查有两个可能的候选项,并且都需要提供哈希代码:
使用数组\u key\u exists()检查密钥是否存在。
检查是否使用isset()设置了密钥。
直截了当地说,isset()比array_key_exists()快,并且在我们的上下文中提供了相同的特性,因此我们将使用它。(事实上,它们处理空值的方式不同,这对我们来说没有什么区别。不会在集合中插入空值。)
考虑到这一点,我们将使用如下方式执行安全壳检查:
array(
$hashcode => $object
);
$object = new stdClass();
$hashkey = spl_object_hash($object);
// ...
// Check whether $arr has the $object.
if (isset($arr[$hashkey])) {
// Do something...
}
同样,使用模拟哈希集的数组允许我们使用所有现有的数组函数,还提供了简单的可重用性。我们可以很容易地将其放入foreach循环并迭代内容。不过,在了解其性能之前,让我们先看看其他可能的解决方案
使用SplObjectStorage
正在考虑的第二种方法使用PHP5.2+中的新SplObjectStorage
类(可能在5.1中)。此类由C实现支持,为类提供了一种类似集合的存储机制。它强化了独特性;每个对象只能存储一个。它也是可遍历的,因为它实现了Iterable接口。这意味着您可以在foreach之类的循环中使用它。(另一方面,PHP5.2中的版本没有
$objectStore = new SplObjectStorage();
$object = new stdClass();
$objectStore->attach($object);
// ...
if ($objectStore->contains($object)) {
// Do something...
}
<?php
/**
* Object hashing tests.
*/
$sos = new SplObjectStorage();
$docs = array();
$iterations = 100000;
for ($i = 0; $i < $iterations; ++$i) {
$doc = new DOMDocument();
//$doc = new stdClass();
$docs[] = $doc;
}
$start = $finis = 0;
$mem_empty = memory_get_usage();
// Load the SplObjectStorage
$start = microtime(TRUE);
foreach ($docs as $d) {
$sos->attach($d);
}
$finis = microtime(TRUE);
$time_to_fill = $finis - $start;
// Check membership on the object storage
$start = microtime(FALSE);
foreach ($docs as $d) {
$sos->contains($d);
}
$finis = microtime(FALSE);
$time_to_check = $finis - $start;
$mem_spl = memory_get_usage();
$mem_used = $mem_spl - $mem_empty;
printf("SplObjectStorage:\nTime to fill: %0.12f.\nTime to check: %0.12f.\nMemory: %d\n\n", $time_to_fill, $time_to_check, $mem_used);
unset($sos);
$mem_empty = memory_get_usage();
// Test arrays:
$start = microtime(TRUE);
$arr = array();
// Load the array
foreach ($docs as $d) {
$arr[spl_object_hash($d)] = $d;
}
$finis = microtime(TRUE);
$time_to_fill = $finis - $start;
// Check membership on the array
$start = microtime(FALSE);
foreach ($docs as $d) {
//$arr[spl_object_hash($d)];
isset($arr[spl_object_hash($d)]);
}
$finis = microtime(FALSE);
$time_to_check = $finis - $start;
$mem_arr = memory_get_usage();
$mem_used = $mem_arr - $mem_empty;
printf("Arrays:\nTime to fill: %0.12f.\nTime to check: %0.12f.\nMemory: %d\n\n", $time_to_fill, $time_to_check, $mem_used);
?>
SplObjectStorage:
Time to fill: 0.085041999817.
Time to check: 0.073099000000.
Memory: 6124624
Arrays:
Time to fill: 0.193022966385.
Time to check: 0.153498000000.
Memory: 8524352
SplObjectStorage:
Time to fill: 0.082209110260.
Time to check: 0.070617000000.
Memory: 6124624
Arrays:
Time to fill: 0.189271926880.
Time to check: 0.152644000000.
Memory: 8524360