array_multisortでソートができなかった話

はじめに
========

array_multisortで引っかかったので備忘録として書きました

# 動作確認環境

|OS|PHP version|
|:--:|:--:|
|Windows 10|7.2.11|

# 確認データ

以下の配列データをranking列の値が低い順にソートします

|weather|ranking|
|:--:|:--:|
|晴れ|2|
|雨|3|
|曇り|1|

# ソートしてみる
## 正しい使い方

まずは正しい使い方を記載します

```php
<?php

// ソート対象
$sort_data = array();
array_push($sort_data, ['weather' => '晴れ', 'ranking' => 2]);
array_push($sort_data, ['weather' => '雨', 'ranking' => 3]);
array_push($sort_data, ['weather' => '曇り', 'ranking' => 1]);

// ソートするキーを設定
$target_keys = array();
foreach ($sort_data as $k => $v)  $target_keys[$k] = $v['ranking'];

// ソート前のデータを出力
print_r("ソート前\n");
print_r($sort_data);

// 昇順ソート
array_multisort($target_keys, SORT_ASC, $sort_data, SORT_NUMERIC);

// ソート後のデータを出力
print_r("ソート後\n");
print_r($sort_data);
```

結果は以下となります

```
ソート前
Array
(
    [0] => Array
        (
            [weather] => 晴れ
            [ranking] => 2
        )

    [1] => Array
        (
            [weather] => 雨
            [ranking] => 3
        )

    [2] => Array
        (
            [weather] => 曇り
            [ranking] => 1
        )

)
ソート後
Array
(
    [0] => Array
        (
            [weather] => 曇り
            [ranking] => 1
        )

    [1] => Array
        (
            [weather] => 晴れ
            [ranking] => 2
        )

    [2] => Array
        (
            [weather] => 雨
            [ranking] => 3
        )

)
```

正しくソートされていますね

## 間違った使い方

間違った使い方です

```php
<?php

// ソート対象
$sort_data = array();
array_push($sort_data, ['weather' => '晴れ', 'ranking' => 2]);
array_push($sort_data, ['weather' => '雨', 'ranking' => 3]);
array_push($sort_data, ['weather' => '曇り', 'ranking' => 1]);

// ソートするキーを設定
$target_keys = array();
foreach ($sort_data as $k => $v)  $target_keys[$k] = $v->ranking;

// ソート前のデータを出力
print_r("ソート前\n");
print_r($sort_data);

// 昇順ソート
array_multisort($target_keys, SORT_ASC, $sort_data, SORT_NUMERIC);

// ソート後のデータを出力
print_r("ソート後\n");
print_r($sort_data);

```

結果は以下となります

```
ソート前
Array
(
    [0] => Array
        (
            [weather] => 晴れ
            [ranking] => 2
        )

    [1] => Array
        (
            [weather] => 雨
            [ranking] => 3
        )

    [2] => Array
        (
            [weather] => 曇り
            [ranking] => 1
        )

)
ソート後
Array
(
    [0] => Array
        (
            [weather] => 晴れ
            [ranking] => 2
        )

    [1] => Array
        (
            [weather] => 雨
            [ranking] => 3
        )

    [2] => Array
        (
            [weather] => 曇り
            [ranking] => 1
        )

)
```

ソートされませんね

# 原因

単純にキーの設定でアロー演算子を使っているのが原因

```php
foreach ($sort_data as $k => $v)  $target_keys[$k] = $v->ranking;
```

対象データは連想配列であるためアロー演算子ではとってこれない
実際に$target_keysの値を見てみると空が入っている

```
Array
(
    [0] =>
    [1] =>
    [2] =>
)
```

アロー演算子でとってくる場合、対象データ以下のように変更する必要がある

```php
<?php

// ソート対象
$sort_data = array();
$data1 = new \stdClass();
$data1->weather = '晴れ';
$data1->ranking = 2;

$data2 = new \stdClass();
$data2->weather = '雨';
$data2->ranking = 3;

$data3 = new \stdClass();
$data3->weather = '曇り';
$data3->ranking = 1;

array_push($sort_data, $data1);
array_push($sort_data, $data2);
array_push($sort_data, $data3);

// array_push($sort_data, ['weather' => '晴れ', 'ranking' => 2]);
// array_push($sort_data, ['weather' => '雨', 'ranking' => 3]);
// array_push($sort_data, ['weather' => '曇り', 'ranking' => 1]);

// ソートするキーを設定
$target_keys = array();
foreach ($sort_data as $k => $v)  $target_keys[$k] = $v->ranking;

// ソート前のデータを出力
print_r("ソート前\n");
print_r($sort_data);

// 昇順ソート
array_multisort($target_keys, SORT_ASC, $sort_data, SORT_NUMERIC);

// ソート後のデータを出力
print_r("ソート後\n");
print_r($sort_data);
```

オブジェクトに入れたものならば大丈夫。当たり前ですね。

# NOTICEエラーを出すようにしよう

初歩的なミスですが、NOTICEエラー非表示で開発していたためこのエラー出力されず30分画面とにらめっこしてました...
NOTICEエラーを出すと以下のようなエラーが出力されます

```
PHP Notice:  Trying to get property 'ranking' of non-object in C:\Users\work\test\test.php on line 11

Notice: Trying to get property 'ranking' of non-object in C:\Users\work\test\test.php on line 11
PHP Notice:  Trying to get property 'ranking' of non-object in C:\Users\work\test\test.php on line 11

Notice: Trying to get property 'ranking' of non-object in C:\Users\work\test\test.php on line 11
PHP Notice:  Trying to get property 'ranking' of non-object in C:\Users\work\test\test.php on line 11

Notice: Trying to get property 'ranking' of non-object in C:\Users\work\test\test.php on line 11
```

開発時はNOTICEエラーを出力するようにしよう...