我可以使用实例化的对象作为数组键吗?
Posted
技术标签:
【中文标题】我可以使用实例化的对象作为数组键吗?【英文标题】:Can I use an instantiated Object as an Array Key? 【发布时间】:2011-06-06 07:00:06 【问题描述】:例如:
$product = new Product("cat");
if(isset($sales[$product]))
$sales[$product]++;
else
$sales[$product] = 1;
【问题讨论】:
【参考方案1】:来自docs:
数组和对象不能用作键。这样做会导致警告:Illegal offset type。
您可以给每个实例一个唯一的 ID 或覆盖 __toString()
以便它返回一些唯一的东西并执行例如
$array[(string) $instance] = 42;
【讨论】:
【参考方案2】:您可以使用http://www.php.net/manual/en/class.splobjectstorage.php
$product = new Product("cat");
$sales = new SplObjectStorage();
if(isset($sales[$product]))
$sales[$product]++;
else
$sales[$product] = 1;
它不是一个真正的数组,但具有相当数量的类似数组的功能和语法。然而,由于它是一个对象,由于它奇怪的 foreach 行为以及它与所有本机 php 数组函数的不兼容,它在 php 中的行为就像一个不合适的人选。有时您会发现通过
将其转换为真实数组很有用$arr = iterator_to_array($sales);
所以它与你的代码库的其余部分配合得很好。
【讨论】:
【参考方案3】:有一个spl_object_hash函数用于获取唯一的对象id作为字符串,可以用作数组键。 http://php.net/manual/en/function.spl-object-hash.php
【讨论】:
实际上来自文档:当一个对象被销毁时,它的 hash 可能会被其他对象重用。因此,通常最好按照 goat 的建议使用 SplObjectStorage。【参考方案4】:仅限integers and strings are allowed as array keys。如果您绝对需要该功能,您可以编写一个实现 ArrayAccess 的类。
【讨论】:
它不允许您将对象用作数组键。它唯一允许的是将对象视为数组,因此对象的属性将是键 它将允许您使用对象作为键。有关示例实现,请参阅 pastebin.com/fzqeFswJ。 我明白你的意思,这是有道理的。我的意思是它不允许您将对象用作 array 键。但是是的,它将允许您使用对象作为 ArrayAccess 对象的键【参考方案5】:如果对象是使用new stdClass()
制作的简单预定义类,则可以使用带有json_encode
的此类的json 表示形式。
$product = new stdClass();
$product->brand = "Acme";
$product->name = "Patator 3.14";
$product_key = json_encode($product);
if(isset($sales[$product_key]))
$sales[$product_key]++;
else
$sales[$product_key] = 1;
但请记住,两个对象的相等性始终是一种商业模式选择,必须仔细设计。
【讨论】:
【参考方案6】:你可以有两个数组:
Array 1 contains the keys: | Array 2 contains the values
+--------+-------------+ | +--------+------------+
| index: | value: | | | index: | value: |
| 0 | Object(key) | | | 0 | sth(value) |
| 1 | Object(key) | | | 1 | sth(value) |
+--------+-------------+ | +--------+------------+
您在数组 1 中搜索对象, 然后你选择那个对象的索引 将其用作数组 2 的索引和 => 获取价值
在php代码中
public function getValue($ObjectIndexOfYourArray)
foreach(array1 as $key => $value)
if($value == ObjectIndexOfYourArray)
return array2[$key];
希望对你有帮助
【讨论】:
【参考方案7】:我知道这个问题已经过时了,而且 SplObjectStorage
有一些奇怪的行为(例如在循环使用 foreach
时)。
截至今天,我编写了一个名为 linked-hash-map
(https://github.com/tonix-tuft/linked-hash-map) 的库,它在 PHP 中实现了关联数组/哈希映射/哈希表,并允许您使用任何 PHP 数据类型作为键:
<?php
use LinkedHashMap\LinkedHashMap;
$map = new LinkedHashMap();
$map[true] = 'bool (true)';
$map[false] = 'bool (false)';
$map[32441] = 'int (32441)';
$map[-32441] = 'int (-32441)';
$map[2147483647] = 'int (2147483647)';
$map[-2147483648] = 'int (-2147483648)';
$map[PHP_INT_MAX - 100] = 'int (PHP_INT_MAX - 100)';
$map[PHP_INT_MIN] = 'int (PHP_INT_MIN)';
$map[0.5] = 'float/double (0.5)';
$map[-0.5] = 'float/double (-0.5)';
$map[123891.73] = 'float/double (123891.73)';
$map[-123891.73] = 'float/double (-123891.73)';
$map[PHP_INT_MAX + 10] = 'float/double (PHP_INT_MAX + 10)';
$map[PHP_INT_MIN - 10] = 'float/double (PHP_INT_MIN - 10)';
$map['abc'] = 'string (abc)';
$map["abcdef"] = "string (abcdef)";
$map['hfudsh873hu2ifl'] = "string (hfudsh873hu2ifl)";
$map["The quick brown fox jumps over the lazy dog"] =
'string (The quick brown fox jumps over the lazy dog)';
$map[[1, 2, 3]] = 'array ([1, 2, 3])';
$map[['a', 'b', 'c']] = "array (['a', 'b', 'c'])";
$map[[1, 'a', false, 5, true, [1, 2, 3, ['f', 5, []]]]] =
"array ([1, 'a', false, 5, true, [1, 2, 3, ['f', 5, []]]])";
class A
$objA = new A();
$map[$objA] = "object (new A())";
// You can even use file handles/resources:
$fp = fopen(__DIR__ . '/private_local_file', 'w');
$map[$fp] = "resource (fopen())";
$ch = curl_init();
$map[$ch] = "resource (curl_init())";
// All the values can be retrieved later using the corresponding key, e.g.:
var_dump($map[[1, 2, 3]]); // "array ([1, 2, 3])"
var_dump($map[$objA]); // "object (new A())"
var_dump($map[$ch]); // "resource (curl_init())"
【讨论】:
【参考方案8】:您终于可以在 PHP 8.0+ 中使用对象作为数组键。但这是一个谎言。它不会是您使用的常规数组,而是the new WeakMap class。
声明一个new WeakMap();
,然后你可以把它装满对象作为键。与任何基于Spl
的技巧相比,使用它的优势在于WeakMap
在内存泄漏方面更好。 “弱”部分是指对象在映射中的引用是“弱”的,并且一旦对象不再在范围内,就不会阻止该对象被垃圾收集。 WeakMap
会自动从自身移除对象。
这里是 a good run-through 的用例。
PHP RFC 也不错。
【讨论】:
以上是关于我可以使用实例化的对象作为数组键吗?的主要内容,如果未能解决你的问题,请参考以下文章