PHP-从对象数组中提取属性


128

我有一系列的猫对象:

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

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

我当时在考虑使用array_walkwith,create_function但我不知道该怎么做。

任何想法?


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

Answers:


149

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

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

但是儿子必须是一个数组或转换为数组


12
这实际上是最好的答案
德米特里·布斯拉耶夫

1
最佳解决方案,但仅适用于php 5.5及更高版本
Ludo-记录中的最高记录为

2
无论如何,没有人应该再用5.5进行编码。3.5岁的编程语言版本...
Toskan

11
该解决方案无法回答问题,因为array_column它根本不能与arrayof 一起使用object。由于可以使用PHP 7.0.0,因此:stackoverflow.com/a/23335938/655224
algorhythm

1
仅当对象属性具有公共访问权限时,它才起作用。
卡罗尔·加西亚尼卡'18

154

create_function()从PHP 7.2.0开始,警告已被弃用。强烈建议不要使用此功能。

您可以使用该array_map()功能。
应该这样做:

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

54
这是正确的解决方案,并会导致每个即将到来的维护人员都将受到“ wtf”的攻击:D
Andreas Klinger 2009年

4
我对此解决方案唯一不满意的地方是使用create_function。
Ionuț G. Stan,2009年

4
您可以使用lambda函数,但是没有多少人会运行PHP 5.3
Greg

26
现在开始:$project_names = array_map(function($project) { return $project->name ;}, $projects );但是,在此博客文章中指出,这种方式可能会慢2.5倍/占用大量内存。
2013年

7
我发现,每次使用create_function内存创建函数时,它都在增长。如果编写具有无限循环的程序并在array_map其中调用with create_function,则总会在某个时间Out of memory...出现错误。所以不要使用create_function和使用array_map(function($o) { return $o->id; }, $objects);
algorhythm 2014年

87

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

第一(较新的PHP版本)

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

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

注意: 要迭代问题中所用的array包含\stdClasses,只能使用PHP版本>= 7.0。但是在使用时,arrayarray是你可以做的,因为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
...


这也可以在这里讨论

内存泄漏?!在“ array_map”中使用“ create_function”时,垃圾收集器是否正确?


虽然我使用的是php 7.2,但如果使用命名空间类对象,则解决方案似乎无法正常工作,并返回空白数组。
穆罕默德·奥默·阿斯兰

您可以发布漏洞利用程序吗?简短的摘要可以更好地了解您的情况?
algorhythm

例如,请参阅此代码段,其中有dropbox API SDK返回的模型对象的列表,当我们尝试array_column在此数组上使用时,它始终返回空白,而代码段可以正常工作,两者都具有protected属性,可在第二个代码段中访问只要。除了命名空间,我找不到其他原因。
穆罕默德·奥默·阿斯兰

当我写object我的解决方案时,我的意思object不是Object。小写字母object描述简单对象\stdClass。也许这就是问题所在。你ObjecttoArray办法吗?用这个。一个简单的objectarray几乎是相同的。以下不变式必须有效:((object)(array)$o) === $o。在实现__get方法时,您将使您的类属性可供所有人访问。这可能是预期的行为。但是您也可以array<Object>使用array_map和调用toArray(如果存在)来遍历您的
实例

我提供的第二个片段来自php,net,并使用与第一个片段相同的Class对象,也许您是对的,也许我会尝试将其转换为感谢数组来尝试其他操作。
穆罕默德·奥默·阿斯兰

4
function extract_ids($cats){
    $res = array();
    foreach($cats as $k=>$v) {
        $res[]= $v->id;
    }
    return $res
}

在一行中使用它:

$ids = extract_ids($cats);

1
感谢SilentGhost,但我的问题是仅在1个命令中获得$ res,而不使用循环...
abernier

2
有什么区别?这几乎是直截了当的。您可能会使用类似的内容使用更多行array_walk
deceze

@deceze,一个优雅,简单而简洁的解决方案看起来更好-特别是对于此操作如此可解释的事情(例如,这不是具有大量空间和注释的自定义逻辑)。对我来说,那有很大的不同。
查理·达萨斯

3

<?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)
}

我知道它使用循环,但这是最简单的方法!而且使用函数,它仍然以一行结尾。


我不明白为什么人们不只是选择这样的简单解决方案。如果您问我,这样做似乎合乎逻辑。
汤姆·代尔


3

create_function()从PHP 7.2.0开始,警告已被弃用。强烈建议不要使用此功能。

PHP中的内置循环比解释性循环要快,因此,使此循环成为单线实际上是有意义的:

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


0
    $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]


0

php v7.2.0开始create_function()不推荐使用该功能。您可以使用给出的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');
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.