【问题标题】:PHP - Extracting a property from an array of objectsPHP - 从对象数组中提取属性
【发布时间】:2010-11-10 06:41:17
【问题描述】:

我有一组猫对象:

$cats = Array
    (
        [0] => stdClass Object
            (
                [id] => 15
            ),
        [1] => stdClass Object
            (
                [id] => 18
            ),
        [2] => stdClass Object
            (
                [id] => 23
            )
)

我想在 1 行中提取一组猫的 ID(不是函数也不是循环)。

我正在考虑将array_walkcreate_function 一起使用,但我不知道该怎么做。

有什么想法吗?

【问题讨论】:

  • 我不想使用循环,因为我希望能够在 1 行中分配结果: $cats_id = myfunction($cats); /* 应该返回 Array(15, 18, 23) */

标签: php


【解决方案1】:

如果您有PHP 5.5 或更高版本,最好的方法是使用内置函数array_column()

$idCats = array_column($cats, 'id');

但是子必须是数组或者转为数组

【讨论】:

  • 此解决方案无法回答问题,因为array_column 根本不适用于objects 的array。由于 PHP 7.0.0 是可能的:stackoverflow.com/a/23335938/655224
  • 只有在对象属性具有公共访问权限时才有效。
【解决方案2】:

警告 create_function() 自 PHP 7.2.0 起已弃用。强烈建议不要依赖此函数。

您可以使用array_map() 函数。
应该这样做:

$catIds = array_map(create_function('$o', 'return $o->id;'), $objects);

正如@Relequestual 在下面所写,该函数现在直接集成在array_map 中。新版本的解决方案如下所示:

$catIds = array_map(function($o) { return $o->id;}, $objects);

【讨论】:

  • 这是正确的解决方案,这将导致每个即将到来的维护者都将被“wtf”:D
  • 我唯一不喜欢这个解决方案的是使用 create_function。
  • 您可以使用 lambda 函数,但运行 PHP 5.3 的人并不多
  • 这里我们开始:$project_names = array_map(function($project) { return $project->name ;}, $projects ); 但是,注意到in this blog post 这样可能会慢 2.5 倍/内存密集。
  • 我发现,每次使用create_function 创建函数时,内存都会增长。如果你编写了一个无限循环的程序,并在其中调用array_mapcreate_function,你总会在某个时候得到Out of memory... 错误。所以不要使用create_function而使用array_map(function($o) { return $o->id; }, $objects);
【解决方案3】:

解决方案取决于您使用的 PHP 版本。至少有两种解决方案:

首先(较新的 PHP 版本)

正如@JosepAlsina 之前所说,最好也是最短的解决方案是使用array_column,如下所示:

$catIds = array_column($objects, 'id');

注意: 要迭代问题中使用的包含\stdClasses 的array,只能使用PHP 版本>= 7.0。但是当使用包含arrays 的array 时,你可以这样做,因为PHP >= 5.5

第二个(旧 PHP 版本)

@Greg 说在旧 PHP 版本中可以执行以下操作:

$catIds = array_map(create_function('$o', 'return $o->id;'), $objects);

但要注意:在较新的 PHP 版本 >= 5.3.0 中,最好使用 Closures,如下所示:

$catIds = array_map(function($o) { return $o->id; }, $objects);


区别

第一个解决方案创建一个新函数并将其放入您的 RAM。由于某种原因,垃圾收集器不会从内存中删除已创建和已调用的函数实例。不管事实如何,创建的函数实例永远不能被再次调用,因为我们没有指向它的指针。并且下次调用此代码时,将再次创建相同的函数。这种行为会慢慢填满你的记忆……

两个例子都有内存输出来比较它们:

不好

while (true)
{
    $objects = array_map(create_function('$o', 'return $o->id;'), $objects);

    echo memory_get_usage() . "\n";

    sleep(1);
}

// the output
4235616
4236600
4237560
4238520
...

while (true)
{
    $objects = array_map(function($o) { return $o->id; }, $objects);

    echo memory_get_usage() . "\n";

    sleep(1);
}

// the output
4235136
4235168
4235168
4235168
...


这也可以在这里讨论

Memory leak?! Is Garbage Collector doing right when using 'create_function' within 'array_map'?

【讨论】:

  • 虽然我使用的是 php 7.2,但如果您使用命名空间类对象,似乎该解决方案将不起作用,并返回空白数组。
  • 你能发布一个漏洞利用吗?简短的 sn-p 以更好地了解您的上下文?
  • 例如,看到这个snippet,我有一个由Dropbox API SDK返回的模型对象列表,当我们尝试在这个数组上使用array_column时它总是返回空白,而THIS sn -p 正常工作,两者都具有仅在第二个 sn-p 中可访问的受保护属性。除了命名空间,我找不到任何其他原因。
  • 当我在我的解决方案中写 object 时,我的意思是 object 不是 Object。小写的object 描述了简单的对象\stdClass。也许这就是问题所在。你的ObjecttoArray 方法吗?用这个。一个简单的object 和一个array 几乎相同。以下不变量必须有效:((object)(array)$o) === $o。实现__get 方法时,您将使每个人都可以访问您的类属性。这可能是预期的行为。但是您也可以遍历您的array<Object>,例如与array_map 并调用toArray(如果存在)然后它也可以工作
  • 我提供的第二个 sn-p 来自 php,net 并使用与第一个 sn-p 中相同的 Class 对象,也许你是对的,也许我会尝试将其转换为数组谢谢。
【解决方案4】:
function extract_ids($cats){
    $res = array();
    foreach($cats as $k=>$v) {
        $res[]= $v->id;
    }
    return $res
}

并在一行中使用它

$ids = extract_ids($cats);

【讨论】:

  • 感谢 SilentGhost,但我的问题是仅在 1 个命令中获取 $res,而不是使用循环...
  • 它有什么不同?这几乎是直截了当的。你可能会使用更多的行,比如array_walk
  • @deceze,一个优雅、简单和简洁的解决方案看起来更好——尤其是对于像这个操作这样可解释的东西(例如,这不是需要大量空间和 cmets 的自定义逻辑)。对我来说,这有很大的不同。
【解决方案5】:

代码

<?php

# setup test array.
$cats = array();
$cats[] = (object) array('id' => 15);
$cats[] = (object) array('id' => 18);
$cats[] = (object) array('id' => 23);

function extract_ids($array = array())
{
    $ids = array();
    foreach ($array as $object) {
        $ids[] = $object->id;
    }
    return $ids;
}

$cat_ids = extract_ids($cats);
var_dump($cats);
var_dump($cat_ids);

?>

输出

# var_dump($cats);
array(3) {
  [0]=>
  object(stdClass)#1 (1) {
    ["id"]=>
    int(15)
  }
  [1]=>
  object(stdClass)#2 (1) {
    ["id"]=>
    int(18)
  }
  [2]=>
  object(stdClass)#3 (1) {
    ["id"]=>
    int(23)
  }
}

# var_dump($cat_ids);
array(3) {
  [0]=>
  int(15)
  [1]=>
  int(18)
  [2]=>
  int(23)
}

我知道它使用循环,但这是最简单的方法!并且使用一个函数,它仍然会在一行中结束。

【讨论】:

  • 我不明白为什么人们不选择这样的简单解决方案。如果你问我,这样做似乎合乎逻辑。
【解决方案6】:

您可以使用ouzo goodies轻松完成此操作

$result = array_map(Functions::extract()->id, $arr);

或使用数组(来自茴香酒)

$result = Arrays::map($arr, Functions::extract()->id);

签出:http://ouzo.readthedocs.org/en/latest/utils/functions.html#extract

另请参阅使用 ouzo 进行函数式编程(我无法发布链接)。

【讨论】:

    【解决方案7】:

    警告 create_function() 自 PHP 7.2.0 起已弃用。强烈建议不要依赖此函数。

    PHP 中的内置循环比解释循环更快,因此将其设置为单线实际上是有意义的:

    $result = array();
    array_walk($cats, create_function('$value, $key, &$result', '$result[] = $value->id;'), $result)
    

    【讨论】:

      【解决方案8】:
      // $array that contain records and id is what we want to fetch a
      $ids = array_column($array, 'id');
      
      【解决方案9】:
          $object = new stdClass();
          $object->id = 1;
      
          $object2 = new stdClass();
          $object2->id = 2;
      
          $objects = [
              $object,
              $object2
          ];
      
          $ids = array_map(function ($object) {
              /** @var YourEntity $object */
              return $object->id;
              // Or even if you have public methods
              // return $object->getId()
          }, $objects);
      

      输出:[1, 2]

      【讨论】:

        【解决方案10】:

        create_function() 函数自 php v7.2.0 起已弃用。您可以按照给定的方式使用 array_map()

        function getObjectID($obj){
            return $obj->id;
        }
        
        $IDs = array_map('getObjectID' , $array_of_object);
        

        或者,您可以使用 array_column() 函数从输入的单个列返回值,由 column_key 标识。可选地,可以提供 index_key 以通过输入数组的 index_key 列中的值对返回数组中的值进行索引。您可以使用给定的array_column,

        $IDs = array_column($array_of_object , 'id');
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-08-22
          • 2023-01-27
          • 2017-10-25
          • 2022-01-10
          相关资源
          最近更新 更多