【问题标题】: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;
}

【问题讨论】:

    标签: php arrays object


    【解决方案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 也不错。

              【讨论】:

                猜你喜欢
                • 2011-11-25
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2021-10-23
                • 1970-01-01
                • 2017-12-27
                • 1970-01-01
                相关资源
                最近更新 更多