web-dev-qa-db-ja.com

オブジェクト/連想配列のためのPHPでの割り当ての破壊

CoffeeScript、Clojure、ES6およびその他の多くの言語では、オブジェクト/マップなどを次のように分解できます。

obj = {keyA: 'Hello from A', keyB: 'Hello from B'}
{keyA, keyB} = obj

私は list function をphpで見つけて、配列を次のように分解できます:

$info = array('coffee', 'brown', 'caffeine');
list($drink, $color, $power) = $info;

PHPでオブジェクトまたは連想配列を分解する方法はありますか?コアライブラリに含まれていない場合、誰かがスマートヘルパー関数を作成した可能性がありますか?

26
Cotten

PHP 7.0以下の場合、listの機能を超えます。ドキュメントの状態:

listは数値配列でのみ機能し、数値インデックスは0から始まると想定しています。

目的に合ったものの1つは、配列から現​​在のシンボルテーブルに変数をインポートする extract() 関数です。 listを使用すると、変数名を明示的に定義できますが、extract()では、このような自由はありません。

連想配列の抽出

extractを使用すると、次のようなことができます。

_<?php

$info = [ 'drink' => 'coffee', 'color' => 'brown', 'power' => 'caffeine' ];
extract($info);

var_dump($drink); // string(6) "coffee"
var_dump($color); // string(5) "brown"
var_dump($power); // string(8) "caffeine"
_

オブジェクトの抽出

オブジェクトの抽出はほとんど同じように機能します。 extractは配列を引数として取るだけなので、オブジェクトのプロパティを配列として取得する必要があります。 _get_object_vars_ はあなたのためにそれを行います。すべてのpublicプロパティをキーとして、それらの値を値として持つ連想配列を返します。

_<?php

class User {

    public $name = 'Thomas';

}

$user = new User();
extract( get_object_vars($user) );

var_dump($name); // string(6) "Thomas"
_

落とし穴

extract()は、シンボルテーブルにエクスポートされる変数名を明示的に定義できないため、listと同じではありません。変数名は、デフォルトで配列キーに対応しています。

  • listは言語構造であり、extract()は関数です
  • 事前に定義した変数を意図せずに上書きしてしまうことがあります
  • 配列キーは変数名として無効である可能性があります

extract()に2番目の引数として渡すことができる_$flags_パラメータを使用すると、変数が衝突したり無効な場合の動作に影響を与えることができます。しかし、それでもextract()の仕組みを理解し、それをcautonで使用することが重要です。

編集:PHP 7.1現在、これは可能です:

http://php.net/manual/en/migration71.new-features.php#migration71.new-features.support-for-keys-in-list

これで、list()またはその新しい省略[]構文でキーを指定できるようになりました。これにより、非整数または非順次キーを持つ配列の構造化解除が可能になります。

https://php.net/manual/en/migration71.new-features.php#migration71.new-features.symmetric-array-destructuring

現在もサポートされている既存のlist()構文の代わりとして、省略形配列構文([])を使用して、割り当て(foreach内を含む)の配列を分解できます。

例えばこれは:

_$test_arr = ['a' => 1, 'b' => 2];
list('a' => $a, 'b' => $b) = $test_arr;
var_dump($a);
var_dump($b);
_

7.1.0以降、以下を出力します

_int(1) 
int(2)
_
36
thpl

受け入れられた回答が、省略表記を使用した例、抽出の使用に関するセキュリティの問題、およびIDEの問題です。

数値配列破壊(PHP 7.1)

PHP 7.1現在、数値配列の破棄( 対称配列の破棄 )は次のようにサポートされています:

<?php
$data = [55, 'John', 'UK'];
[$id, $name] = $data; // short-hand (recommended)
list($id, $name) = $data; // long-hand

アイテムが必要ない場合は、見落とす可能性があることに注意してください。

連想配列の破棄(PHP 7.1)

次のように、連想配列( リスト内のキーのサポート )で配列を破壊することもできます。

<?php
$data = ['id' => 55, 'firstName' => 'John', 'country' => 'UK']
['id' => $id, 'firstName' => $name] = $data; // short-hand (recommended)
list('id' => $id, 'firstName' => $name) = $data; // long-hand

アイテムが必要ない場合は、見落とす可能性があることに注意してください。また、変数名はプロパティ名と異なる場合があります。

オブジェクトの破棄(PHP 7.1)

残念ながら、オブジェクトの破壊はありません。ただし、 get_object_vars を使用してオブジェクトを連想配列に変換してから、連想配列の破棄を使用できます。

<?php
class User {
    public $id;
    public $name;
    public $country;
}

$user = new User();
$user->id = 55;
$user->name = 'John';
$user->country = 'UK';

['id' => $id, 'firstName' => $name] = get_object_vars($user)

しかし、これはいくつかのIDE=機能を壊す可能性があります。これらは、PHPStorm 2019.1を使用しているときに気付いたいくつかの問題です。

  • IDEは変数のタイプを理解できない可能性があるため、オートコンプリート機能を維持するために@var Type PHPDocsを追加する必要があります
  • リファクタリングツールではうまく機能しません。たとえば、いずれかのプロパティの名前を変更しても、配列を破壊する部分の名前は自動的に変更されません。

だから私はそれを通常の方法でやることをお勧めします:

$id = $user->id
$name = $user->firstName

extractは使用しないでください

抽出では、すべての変数が常に設定されます。そこでそれを使用することは本当に悪い考えです:

  • セキュリティ上の問題が発生する可能性があります。注意していても、将来的には明らかでないセキュリティホールにつながる可能性があります。使用する場合は、悪意のあるハッカーの日を作りたくない限り、ユーザー入力($_GET$_POSTなど)で使用しないでください。
  • バグの検出が困難になる可能性があります
  • 将来クラスまたは配列が変更された場合、新しいプロパティを導入することにより、EXTR_SKIPフラグなどを使用しない限り、すでに使用されている変数と一致するとコードが破損する可能性があります。
4
Yahya Uddin

変数変数は、これを行う1つの方法です。 foreachはスコープ内に留まるため、次のように配列から変数を明示的に定義できます。

$args = ['a' => 1, 'b' => 2, 'c' => 3];
foreach (['a', 'c'] as $v) $$v = $args[$v];
// $a is 1, $b is undefined, $c is 3

それは本当にきれいではなく、ありがたいことにこれは7.1で https://wiki.php.net/rfc/short_list_syntax によって対処されています。これは['a' => $a, 'c' => $c] = $args;上記の例では。

7.1にはassoc配列キーとは異なる名前をvarに使用する方法が含まれているため、ここでも私のアプローチを使用すると、これは非常に簡単です。

foreach (['a' => 'eh', 'b' => 'bee'] as $k => v) $$v = $args[$k];
// $eh is 1, $bee is 2
0