はもちくわ

コードについて書いていきます。

【PHP】foreachの「$key=>」ってなに?(multisortの使い方)

foreachは、配列に入っているデータ分ループして、データが終わると自動で止まってくれるとても便利な命令です。

サーバーのデータベースからPHPでデータ処理を行う時など、本当によく使いますが、PHPを扱い始めたばかりの頃は「 $key=> 」の意味が、よくわからず、記述しなくても配列のデータを取り出せるので、「 $key=> 」は記述せずに使ってました。最近やっと理解できたので、そのへんを整理して書いてみようと思います。

 

まず、foreach文の使い方です。

f:id:hamochikuwa440:20210223002900p:plain

上の絵は、連想配列で['id']と['name']のキーで準備された6つのデータを、foreach文を使って表示しています。上記のように、「$key =>」があるパターンと無いパターンがありますが、どちらも同じ結果です。

 

表示で違いを出すようにすると次のようになります。 

f:id:hamochikuwa440:20210223004007p:plain

echoに$keyを追加してます。そうすると、上の絵の赤い丸のところのように、表示されます。キーは配列の住所と私は理解していますが、そのキーが表示されるわけです。

 

ですが、配列の値をIF文で検索して、該当したら表示する、もしくは準備していた変数に入れて次の処理、という使い方が多いので、「キー使わないし、書き方も=>ってよくわからないし、無くても動くし、まあ書かなくてもいいか」と考えてました。

 

自分が理解してないコードを書いて、エラー出ても、後で見返しても分からないとなるとどうにもならないですからね。なので、配列の場所を調べたいときは、下のようなIF文で順番を調べて指定していました。

f:id:hamochikuwa440:20210223005421p:plain

特に配列の値や順番が変わらない固定的なものであれば、これで問題ありません。そのため、壁にあたるまではずーーーーっとこのめんどくさい方法をとっていました。

 

ただ、先に書いたように、「順番が変わらなければ問題ない」だけであって、配列はキーを維持したまま順番が変わることがあるのです。むしろキーを維持したまま変わるほうが私は多い。。。

 

キーを維持したまま、順番が変わることを再現するため、最初の配列データのキーを直接指定して変更し、上と同じコードで「徳川」さんをIF文で検索して表示させます。すると、次のような結果になります。

 

f:id:hamochikuwa440:20210223201555p:plain



キーが順番と違うので、検索した順番を指定して表示すると、結果が変わってしまいます。このように、条件によって結果が変わってしまうコードは、意図してない場合、とても困りますし、理解してなければ原因を調べるだけで大変な労力です。

 

そこで、ちゃんとforeachの「 $key=> 」を理解しようと考えました。そして、私が理解した命令文の解釈は下のようになります。

 

f:id:hamochikuwa440:20210223010358p:plain

こんな感じだと思います。配列を順番通りに取り出す命令で、繰り返すごとに必ずキーと値がセットでやってくる。なので、次のように書けば解決します。

 

f:id:hamochikuwa440:20210223010919p:plain

 

これで解決です。

そして、「$key =>」はよく連想配列のときに使うのように紹介されますが、普通の配列でも使えます。使い方は上の連想配列と同じですが、実際に書くと下のようになります。

 

f:id:hamochikuwa440:20210223011151p:plain

これで、カウンターをつけて検索しなくても、いつも値と一緒にやってきてくれるキーを使ったほうが楽になりました。

これ書きながら思ったんですが、foreach文のコードの説明のときは、だいたいキーを$keyで表しますよね。だから$keyが自由に名前が変更できる変数っぽくないから混乱するんじゃないですか?!だってコードの一部みたいですもん。

だからforeach( $data as $k => $d )でいいんですよ。

 

さて、ここまで、配列の並び替えを無視してやってまいりました。もちろん並び替えもできます。ここまで使ってきた$dataの配列をキーの順番に並び替えるなら、ksort($data)で昇順、krsort($data)で降順。値で並び替えるなら、asort($data)で昇順、arsort($data)で降順です。

しかし、データベースから持ってきた連想配列でカラムによって値がいくつかあるとき、asortって値での並び替えだけど、どのカラムが基準になるの?となりますよね。これは、並びが最初のカラムの値を基準にして変わるようです。上の配列なら['id']ですね。データベースからのデータなら、そもそもユニークな値のカラムがないと編集ができないので、大体はid作ってオートインクリメントにしたりしますよね。だから、その値を最初にくるように設計していれば、上の関数一発で解決する気がします。

 

ですが!最初にも書きましたが、どんな値が来ても想定した動きができるようになってないと、やはりちょっと怖いですよね。それに、Excelのフィルターとか並び替えのように、特定のカラムをキーにして並び替える需要も結構あります。最後にそんな並び替えをするための、array_multisort( )の解釈を紹介します。

 

array_multisort( )の使い方

 

f:id:hamochikuwa440:20210223020314p:plain

 

ちょっと複雑に見えますが、何をやっているのかと言いますと、連想配列$dataの['id']というカラムを指定して並び替えるという関数はなく、単独では解決できません。

そこで、array_multisort( )を使うのですが、並び替えのキーとなるカラムの情報を配列にする必要があります。

そのため、先に$dataから['id']のカラムデータを「別の新しい配列のコピーを作成」します。その方法として、上の絵の四角のように2通りありますが、array_columnはPHP5.5以降しか使えません。古いシステムで動いている場合は注意が必要ですね。。。

 

array_columnのほうがコードがスッキリしていて、見やすいですが、コピーを作成すると考えると、array_columnよりforeachで配列を作っている方が理解しやすいですね。$dataのキーと同じように['id']カラムデータから配列$idを作っているわけです。

 

そして、マルチソートを使い、先に作った$idを並び替え、$idのキーに習って$dataを並び替えるということをするわけです。

また、複数のカラムを指定することも可能です。その際は、指定するカラムごとに配列を準備する必要があります。このような複数指定するキーがある場合、array_columnのほうがコードがスッキリして良さそうですね。マルチソートのほうは、「コピーしたキーの配列」「並び替え基準」を元の配列の前に追加していけば使えます。

 

以上が、私なりの理解、解釈になります。すこし表現がおかしいかもしれません。いまのところ、このように考えて使っていて不具合はでてませんので、大丈夫だと思いますが、おかしなことがあれば、すぐに訂正していきます。