3 フォロワー

ArrayHelper

豊富なPHP配列関数のセットに加えて、Yiiの配列ヘルパーは、配列をより効率的に扱うことができる追加の静的メソッドを提供します。

値の取得

標準的なPHPを使用して配列、オブジェクト、またはその両方からなる複雑な構造から値を取得するのは、非常に反復的です。最初に`isset`を使用してキーが存在するかどうかを確認し、存在する場合は取得し、存在しない場合はデフォルト値を提供する必要があります。

class User
{
    public $name = 'Alex';
}

$array = [
    'foo' => [
        'bar' => new User(),
    ]
];

$value = isset($array['foo']['bar']->name) ? $array['foo']['bar']->name : null;

Yiiはこれを行うための非常に便利なメソッドを提供します。

$value = ArrayHelper::getValue($array, 'foo.bar.name');

最初のメソッド引数は、値を取得する場所です。2番目の引数は、データの取得方法を指定します。以下のいずれかになります。

  • 値を取得する配列キー名またはオブジェクトのプロパティ名。
  • ドットで区切られた配列キーまたはオブジェクトのプロパティ名のセット。上記の例で使用したもの。
  • 値を返すコールバック。

コールバックは以下のようになります。

$fullName = ArrayHelper::getValue($user, function ($user, $defaultValue) {
    return $user->firstName . ' ' . $user->lastName;
});

3番目のオプションの引数はデフォルト値で、指定されていない場合は`null`です。以下のように使用できます。

$username = ArrayHelper::getValue($comment, 'user.username', 'Unknown');

値の設定

$array = [
    'key' => [
        'in' => ['k' => 'value']
    ]
];

ArrayHelper::setValue($array, 'key.in', ['arr' => 'val']);
// the path to write the value in `$array` can be specified as an array
ArrayHelper::setValue($array, ['key', 'in'], ['arr' => 'val']);

その結果、`$array['key']['in']`の初期値は新しい値で上書きされます。

[
    'key' => [
        'in' => ['arr' => 'val']
    ]
]

パスに存在しないキーが含まれている場合は、キーが作成されます。

// if `$array['key']['in']['arr0']` is not empty, the value will be added to the array
ArrayHelper::setValue($array, 'key.in.arr0.arr1', 'val');

// if you want to completely override the value `$array['key']['in']['arr0']`
ArrayHelper::setValue($array, 'key.in.arr0', ['arr1' => 'val']);

結果は次のようになります。

[
    'key' => [
        'in' => [
            'k' => 'value',
            'arr0' => ['arr1' => 'val']
        ]
    ]
]

配列からの値の取得

値を取得してすぐに配列から削除する場合は、`remove`メソッドを使用できます。

$array = ['type' => 'A', 'options' => [1, 2]];
$type = ArrayHelper::remove($array, 'type');

コード実行後、$arrayには['options' => [1, 2]]が、$typeにはAが格納されます。getValueメソッドとは異なり、removeは単純なキー名のみをサポートすることに注意してください。

キーの存在確認

ArrayHelper::keyExistsは、大文字と小文字を区別しないキー比較もサポートする点を除いて、array_key_existsと同様に機能します。例えば、

$data1 = [
    'userName' => 'Alex',
];

$data2 = [
    'username' => 'Carsten',
];

if (!ArrayHelper::keyExists('username', $data1, false) || !ArrayHelper::keyExists('username', $data2, false)) {
    echo "Please provide username.";
}

カラムの取得

データ行またはオブジェクトの配列から値のカラムを取得する必要があることがよくあります。一般的な例としては、IDのリストを取得することが挙げられます。

$array = [
    ['id' => '123', 'data' => 'abc'],
    ['id' => '345', 'data' => 'def'],
];
$ids = ArrayHelper::getColumn($array, 'id');

結果は['123', '345']となります。

追加の変換が必要な場合、または値の取得方法が複雑な場合、2番目の引数に無名関数として指定できます。

$result = ArrayHelper::getColumn($array, function ($element) {
    return $element['id'];
});

配列の再インデックス

指定されたキーに従って配列にインデックスを付けるには、indexメソッドを使用できます。入力は、多次元配列またはオブジェクトの配列のいずれかである必要があります。$keyは、サブ配列のキー名、オブジェクトのプロパティ名、またはキーとして使用される値を返す無名関数のいずれかになります。

$groups属性は、指定されたキーに基づいて入力配列を1つ以上のサブ配列にグループ化するために使用されるキーの配列です。

特定の要素の$key属性またはその値がnullであり、$groupsが定義されていない場合、配列要素は破棄されます。それ以外の場合、$groupsが指定されている場合、配列要素はキーなしで結果配列に追加されます。

例えば

$array = [
    ['id' => '123', 'data' => 'abc', 'device' => 'laptop'],
    ['id' => '345', 'data' => 'def', 'device' => 'tablet'],
    ['id' => '345', 'data' => 'hgi', 'device' => 'smartphone'],
];
$result = ArrayHelper::index($array, 'id');

結果は、キーがid属性の値である連想配列になります。

[
    '123' => ['id' => '123', 'data' => 'abc', 'device' => 'laptop'],
    '345' => ['id' => '345', 'data' => 'hgi', 'device' => 'smartphone']
    // The second element of an original array is overwritten by the last element because of the same id
]

$keyとして渡された無名関数は、同じ結果になります。

$result = ArrayHelper::index($array, function ($element) {
    return $element['id'];
});

3番目の引数としてidを渡すと、$arrayidでグループ化されます。

$result = ArrayHelper::index($array, null, 'id');

結果は、最初のレベルでidでグループ化され、2番目のレベルではインデックス付けされていない多次元配列になります。

[
    '123' => [
        ['id' => '123', 'data' => 'abc', 'device' => 'laptop']
    ],
    '345' => [ // all elements with this index are present in the result array
        ['id' => '345', 'data' => 'def', 'device' => 'tablet'],
        ['id' => '345', 'data' => 'hgi', 'device' => 'smartphone'],
    ]
]

グループ化配列にも無名関数を使用できます。

$result = ArrayHelper::index($array, 'data', [function ($element) {
    return $element['id'];
}, 'device']);

結果は、最初のレベルでid、2番目のレベルでdeviceでグループ化され、3番目のレベルでdataでインデックス付けされた多次元配列になります。

[
    '123' => [
        'laptop' => [
            'abc' => ['id' => '123', 'data' => 'abc', 'device' => 'laptop']
        ]
    ],
    '345' => [
        'tablet' => [
            'def' => ['id' => '345', 'data' => 'def', 'device' => 'tablet']
        ],
        'smartphone' => [
            'hgi' => ['id' => '345', 'data' => 'hgi', 'device' => 'smartphone']
        ]
    ]
]

マップの作成

多次元配列またはオブジェクトの配列からマップ(キーと値のペア)を作成するには、mapメソッドを使用できます。$from$toパラメータは、マップを設定するキー名またはプロパティ名を指定します。必要に応じて、グループ化フィールド$groupに従ってマップをさらにグループ化できます。例えば、

$array = [
    ['id' => '123', 'name' => 'aaa', 'class' => 'x'],
    ['id' => '124', 'name' => 'bbb', 'class' => 'x'],
    ['id' => '345', 'name' => 'ccc', 'class' => 'y'],
];

$result = ArrayHelper::map($array, 'id', 'name');
// the result is:
// [
//     '123' => 'aaa',
//     '124' => 'bbb',
//     '345' => 'ccc',
// ]

$result = ArrayHelper::map($array, 'id', 'name', 'class');
// the result is:
// [
//     'x' => [
//         '123' => 'aaa',
//         '124' => 'bbb',
//     ],
//     'y' => [
//         '345' => 'ccc',
//     ],
// ]

多次元ソート

multisortメソッドは、オブジェクトまたはネストされた配列の配列を1つ以上のキーでソートするのに役立ちます。例えば、

$data = [
    ['age' => 30, 'name' => 'Alexander'],
    ['age' => 30, 'name' => 'Brian'],
    ['age' => 19, 'name' => 'Barney'],
];
ArrayHelper::multisort($data, ['age', 'name'], [SORT_ASC, SORT_DESC]);

ソート後、$dataには次のようになります。

[
    ['age' => 19, 'name' => 'Barney'],
    ['age' => 30, 'name' => 'Brian'],
    ['age' => 30, 'name' => 'Alexander'],
];

ソートするキーを指定する2番目の引数は、単一キーの場合は文字列、複数のキーの場合は配列、または次の無名関数のいずれかになります。

ArrayHelper::multisort($data, function($item) {
    // sort by age if it exists or by name otherwise
    return isset($item['age']) ? $item['age'] : $item['name'];
});

3番目の引数は方向です。単一キーでソートする場合、SORT_ASCまたはSORT_DESCのいずれかになります。複数の値でソートする場合は、ソート方向の配列を提供することで、各値を異なる方法でソートできます。

最後の引数はPHPのソートフラグで、PHPのsort()に渡されるものと同じ値を取ることができます。

配列の種類の検出

配列がインデックス付きか連想型かを把握しておくことは便利です。例を以下に示します。

// no keys specified
$indexed = ['Qiang', 'Paul'];
echo ArrayHelper::isIndexed($indexed);

// all keys are strings
$associative = ['framework' => 'Yii', 'version' => '2.0'];
echo ArrayHelper::isAssociative($associative);

HTMLエンコーディングとデコーディング値

文字列の配列内の特殊文字をHTMLエンティティにエンコードまたはデコードするには、次のものを使用できます。

$encoded = ArrayHelper::htmlEncode($data);
$decoded = ArrayHelper::htmlDecode($data);

デフォルトでは値のみがエンコードされます。2番目の引数をfalseとして渡すことで、配列のキーもエンコードできます。エンコーディングはアプリケーションの文字セットを使用し、3番目の引数で変更できます。

配列のマージ

ArrayHelper::merge()を使用して、2つ以上の配列を再帰的に1つにマージできます。各配列に同じ文字列キー値を持つ要素がある場合、後者は前者を上書きします(array_merge_recursive()とは異なります)。両方の配列に配列型の要素があり、同じキーを持っている場合、再帰的なマージが行われます。整数キーの要素の場合、後者の配列からの要素は前者の配列に追加されます。前の配列から値を削除するにはyii\helpers\UnsetArrayValueオブジェクトを使用し、再帰的なマージの代わりに前の値を強制的に置き換えるにはyii\helpers\ReplaceArrayValueを使用できます。

例えば

$array1 = [
    'name' => 'Yii',
    'version' => '1.1',
    'ids' => [
        1,
    ],
    'validDomains' => [
        'example.com',
        'www.example.com',
    ],
    'emails' => [
        'admin' => 'admin@example.com',
        'dev' => 'dev@example.com',
    ],
];

$array2 = [
    'version' => '2.0',
    'ids' => [
        2,
    ],
    'validDomains' => new \yii\helpers\ReplaceArrayValue([
        'yiiframework.com',
        'www.yiiframework.com',
    ]),
    'emails' => [
        'dev' => new \yii\helpers\UnsetArrayValue(),
    ],
];

$result = ArrayHelper::merge($array1, $array2);

結果は次のようになります。

[
    'name' => 'Yii',
    'version' => '2.0',
    'ids' => [
        1,
        2,
    ],
    'validDomains' => [
        'yiiframework.com',
        'www.yiiframework.com',
    ],
    'emails' => [
        'admin' => 'admin@example.com',
    ],
]

オブジェクトを配列に変換

オブジェクトまたはオブジェクトの配列を配列に変換する必要があることがよくあります。最も一般的なケースは、REST APIを介してデータ配列を提供したり、その他の方法で使用するために、アクティブレコードモデルを変換することです。これを行うには、次のコードを使用できます。

$posts = Post::find()->limit(10)->all();
$data = ArrayHelper::toArray($posts, [
    'app\models\Post' => [
        'id',
        'title',
        // the key name in array result => property name
        'createTime' => 'created_at',
        // the key name in array result => anonymous function
        'length' => function ($post) {
            return strlen($post->content);
        },
    ],
]);

最初の引数には、変換するデータが含まれています。この例では、Post ARモデルを変換しています。

2番目の引数は、クラスごとの変換マッピングです。Postモデルのマッピングを設定しています。各マッピング配列には、一連のマッピングが含まれています。各マッピングは次のようになります。

  • そのまま含めるフィールド名。
  • 目的の配列キー名と、値を取得するモデル列名のキーと値のペア。
  • 目的の配列キー名と、値を返すコールバックのキーと値のペア。

単一モデルに対する上記の変換の結果は次のようになります。

[
    'id' => 123,
    'title' => 'test',
    'createTime' => '2013-01-01 12:00AM',
    'length' => 301,
]

そのクラスでArrayableインターフェースを実装することで、特定のクラスに対するオブジェクトを配列に変換するデフォルトの方法を提供できます。

配列に対するテスト

要素が配列内にあるか、要素のセットが別のセットの部分集合であるかをチェックする必要があることがよくあります。PHPはin_array()を提供していますが、これは部分集合または\Traversableオブジェクトをサポートしていません。

これらの種類のテストを支援するために、yii\helpers\ArrayHelperは、in_array()と同じシグネチャを持つisIn()isSubset()を提供します。

// true
ArrayHelper::isIn('a', ['a']);
// true
ArrayHelper::isIn('a', new ArrayObject(['a']));

// true 
ArrayHelper::isSubset(new ArrayObject(['a', 'c']), new ArrayObject(['a', 'b', 'c']));

タイプミスを見つけた場合、またはこのページの改善が必要だと考える場合は、
githubで編集してください。 !