【问题标题】:Php, check if object with property = value exists in array of objectsPhp,检查具有属性=值的对象是否存在于对象数组中
【发布时间】:2013-09-10 22:44:06
【问题描述】:

我想我可以用这样的 foreach 循环来做到这一点:

 foreach ($haystack as $item)
       if (isset($item->$needle_field) && $item->$needle_field == $needle)
            return true;
 } 

但我在徘徊是否可以在没有循环的情况下完成?

类似:

  if(in_array($item->$needle_field == $needle,$haystack)
            return true;

【问题讨论】:

    标签: php arrays object


    【解决方案1】:

    是的,在现代 PHP 中,您可以通过结合 array_column()(已经发展到也可以处理对象数组)和 in_array() 的力量来确定特定对象属性是否包含特定值而无需经典循环。

    代码:(Demo)

    $objects = [
        (object)['cats' => 2],
        (object)['dogs' => 2],
        (object)['fish' => 10],
        (object)['birds' => 1],
    ];
    
    $needleField = 'cats';
    $needleValue = 2;
    
    var_export(
        in_array($needleValue, array_column($objects, $needleField))
    );
    // output: true
    

    这种技术的优点是语法明显简洁。对于相对少量的数据,这是一种完全可以接受的方法。

    此技术的一个可能缺点是array_column() 将生成一个包含与$needleField 相关的所有值的新数组。

    在我上面的演示中,array_column() 只会生成一个单元素数组,因为所有对象中只有一个 cats 属性。如果我们正在处理相对大量的数据,那么在只需要一个匹配来返回 true 时,费心收集所有符合条件的 cats 值然后运行 ​​in_array() 将是低效的。

    对于“大量”数据,其中性能是脚本设计的主要标准,经典的foreach 循环将是更好的选择,一旦对象满足规则,则应通过@987654334 停止循环@ 或break。

    代码:(Demo)

    function hasPropertyValue(array $objects, $property, $value): bool {
        foreach ($objects as $object) {
            if (property_exists($object, $property) && $object->{$property} === $value) {
                return true;
            }
        }
        return false;
    }
    var_export(
        hasPropertyValue($objects, $needleField, $needleValue)
    );
    

    【讨论】:

      【解决方案2】:

      这是可能的,但也不是更好:

      <?php
      function make_subject($count, $success) {
          $ret = array();
          for ($i = 0; $i < $count; $i++) {
              $object = new stdClass();
              $object->foo = $success ? $i : null;
              $ret[] = $object;
          }
          return $ret;
      }
      
      // Change true to false for failed test.
      $subject = make_subject(10, true);
      
      if (sizeof(array_filter($subject, function($value) {
          return $value->foo === 3;
      }))) {
          echo 'Value 3 was found!';
      } else {
          echo 'Value 3 was not found.';
      }
      

      输出Value 3 was found!。

      我建议您保留 for 循环:它清晰易读,不像保存您可能找到的行的任何技巧。

      【讨论】:

      • 这将比 OP 的代码效率低,因为 array_filter() 将遍历整个数组(即使它已经找到了一个限定值)。 array_filter() 包含一个 return 但这只是在响应中传递一个或多个布尔评估——它实际上并没有停止输入数组的迭代。此外,sizeof() 调用可以安全地从条件中省略。
      【解决方案3】:

      如果您正在搜索的数组超出您的控制范围,这将不起作用。 但是,如果您是构建要搜索的对象数组的人,您可以使用 needle 作为数组键来构建它,以便在搜索时与 array_key_exists 一起使用。

      例如,不要像这样创建 $haystack 数组:

      [
        {
          'needle_field' => $needle
        },
        ...
      ]
      

      把它变成这样:

      [
        $needle => {
          'needle_field' => $needle
        },
        ...
      ]
      

      然后像这样搜索:

      if (array_key_exists($needle, $haystack)) {
        return true;
      }
      

      最后,如果需要,您可以使用array_values 转换回整数索引数组

      $haystack = array_values($haystack);
      

      这可能不适用于所有情况,但对我来说效果很好。

      【讨论】:

        【解决方案4】:

        也许array_key_exists:

        if (array_key_exists($needle_field, $haystack) { 
          if ($haystack[$needle_field] == $needle) {
            echo "$needle exists";
          }
        }
        

        【讨论】:

          猜你喜欢
          • 2020-11-30
          • 2012-11-12
          • 2013-07-03
          • 2019-03-31
          • 2023-03-26
          • 2012-07-27
          • 1970-01-01
          • 2014-01-01
          • 1970-01-01
          相关资源
          最近更新 更多