PHP-オブジェクトの配列からプロパティを抽出する


128

私は猫オブジェクトの配列を持っています:

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

猫のIDの配列を1行で抽出したいと思います(関数でもループでもありません)。

での使用array_walkを考えcreate_functionていましたが、どうすればいいのかわかりません。

何か案が?


1行で結果を割り当てることができるようにしたいので、ループを使用したくありません。$ cats_id = myfunction($ cats); / *はArray(
15、18、23

回答:


149

あなたが持っている場合は、後でPHP 5.5以上を、最良の方法は、機能で構築を使用することですarray_column()

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

しかし、息子は配列であるか、配列に変換されなければなりません


12
これが実際に最良の答えです
Dmitry Buslaev 2016年

1
最善の解決策ですが、php 5.5以降でのみ利用可能です
Ludo-オフレコ

2
とにかく、5.5でこれ以上コーディングする必要はありません。3.5年前のプログラミング言語バージョン...
Toskan

11
、これの解決策は、質問に答えていないarray_columnと動作しないarrayobjectすべてでS。PHP 7.0.0が可能なため:stackoverflow.com/a/23335938/655224
algorhythm

1
オブジェクトプロパティにパブリックアクセスがある場合にのみ機能します。
Karol Gasienica

154

警告 create_function()は、PHP 7.2.0で廃止されました。この機能に依存することはお勧めできません。

array_map()関数を使用できます。
これはそれを行うはずです:

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

54
これは正しい解決策であり、今後のすべてのメンテナが「wtf」されるという事実につながります:D
Andreas Klinger

4
このソリューションで私が嫌いなのは、create_functionの使用だけです。
Ionuț G. Stan

4
ラムダ関数を使用することはできますが、PHP 5.3を実行する人はそれほど多くありません
Greg

26
ここに行きます:$project_names = array_map(function($project) { return $project->name ;}, $projects );ただし、このブログの投稿では、この方法の方が2.5倍遅い/メモリを大量に消費する可能性があることが指摘さています。
13

7
私は、関数がcreate_functionメモリで作成されるたびに成長していることを発見しました。無限ループを含むプログラムを記述し、その中でarray_mapwith を呼び出すと、いつかcreate_functionは常にOut of memory...エラーが発生します。したがってcreate_function、使用しないでくださいarray_map(function($o) { return $o->id; }, $objects);
アルゴリズム

87

解決策は、使用しているPHPのバージョンによって異なります。少なくとも2つの解決策があります。

最初(新しいPHPバージョン)

@JosepAlsinaが前に言ったように、最善かつ最短の解決策はarray_column次のように使用することです:

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

注意:質問で使用されているようにarray包含\stdClassesを 反復する場合、PHPバージョンでのみ可能です>= 7.0。しかし、array包含arraysを使用する場合、PHPから同じことができます>= 5.5

2番目(古いPHPバージョン)

@Gregは、古いバージョンのPHPでは次のことを実行できると述べています。

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

ただし、注意してください。新しいPHPバージョン>= 5.3.0ではClosure、次のようにs を使用することをお勧めします。

$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を使用していますが、名前空間クラスオブジェクトを使用していて、空の配列を返す場合、ソリューションは機能しないようです。
Muhammad Omer Aslam

エクスプロイトを投稿できますか?コンテキストをよりよく理解するための短いスニペット?
アルゴリズム

たとえば、Dropbox API SDKによって返されたモデルオブジェクトのリストがあるこのスニペットを参照してください。このarray_column配列で使用しようとすると、常に空白を返しますが、このスニペットは正しく機能しますが、どちらも2番目のスニペットでアクセスできるprotectedプロパティがありますのみ。名前空間以外の理由は見つかりませんでした。
ムハンマドオメルアスラム

objectが自分のソリューションを書くとき、私はそうではありobjectませんObject。小文字objectは単純なオブジェクトを表します\stdClass。多分それが問題です。あなたはないObject持っているtoArray方法を?これを使って。シンプルobjectarrayはほぼ同じです。次の不変式が有効でなければなりません:((object)(array)$o) === $o__getメソッドを実装する場合、クラスのプロパティに誰でもアクセスできるようにします。これは予想される動作です。しかし、array<Object>たとえば、with array_maptoArray(存在する場合)呼び出しを反復処理して、ITも機能します
アルゴリズム

私が提供した2番目のスニペットはphp、netからのものであり、最初のスニペットと同じClassオブジェクトを使用しています。
ムハンマドオメルアスラム

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

1行で使用します。

$ids = extract_ids($cats);

1
SilentGhostに感謝しますが、私の質問は、ループを使用せずに1つのコマンドで$ resを取得することです...
abernier

2
どんな違いがあるの?これは、簡単なことです。あなたはおそらくのようなものを使用してより多くの行を使用するでしょうarray_walk
だます

@decezeは、エレガントでシンプルで簡潔なソリューションの方が見栄えがよくなります。特に、この操作のように説明できるもの(たとえば、これは多くのスペースとコメントに値するカスタムロジックではありません)です。私にとって、それは大きな違いを生みます。
Charlie Dalsass

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

ループの使用は知っていますが、それが最も簡単な方法です。そして、関数を使用すると、それでも1行になります。


人々がなぜこのような単純な解決策を選ばないのか理解できません。あなたが私に尋ねるなら、このようにそれをするのは理にかなっているようです。
トムダイア


3

警告 create_function()は、PHP 7.2.0で廃止されました。この機能に依存することはお勧めできません。

PHPの組み込みループはインタープリタードループよりも高速であるため、これを1行にするのは実際に意味があります。

$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

この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');
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.