🔰はじめての方へ

【PHP入門】サイドバーのメニューを「配列」と「foreach」でまとめて作る書き方

AI
記事内に広告が含まれています。
スポンサーリンク

今回は、Webサイトのサイドバー(画面の右側にあるメニュー)を作ったときに出会った、PHPの書き方について紹介します。

最初に見たときは「なにこれ?」と思った書き方でしたが、ひとつずつ分解してみると、とても便利な仕組みでした。

PHPを触り始めたばかりの方にもわかるように、順番に説明していきます

例として、架空のカフェのサイトを使います。

サイドバーに「お店について」と「メニュー」の2つのグループがあり、それぞれにページへのリンクが並んでいる、という場面を想像してください。

(👇例:このサイトで言うと、右のサイト内検索やprofileのところを作成します。)

(👇例:そして右側には、左側に画像、右側に文字というリンクを作ります)

1. まずは完成形のコードを見てみよう

最初に、全体のコードを載せます。

いきなり全部わからなくても大丈夫です。

このあと、上から順番に説明します。

<?php
$current = basename($_SERVER['SCRIPT_NAME']);

$menus = [
    'お店について' => ['icon-store', [
        'about.php'  => ['お店の紹介', 'about.jpg'],
        'access.php' => ['アクセス', 'access.jpg'],
    ]],
    'メニュー' => ['icon-cup', [
        'coffee.php' => ['コーヒー', 'coffee.jpg'],
        'cake.php'   => ['ケーキ', 'cake.jpg'],
    ]],
];
?>

<?php foreach ($menus as $heading => [$headingIcon, $links]): ?>
    <nav>
        <p><?php echo $heading; ?></p>
        <ul>
            <?php foreach ($links as $file => [$label, $image]): ?>
                <li>
                    <a<?php if ($file === $current): ?> class="is-current"<?php endif; ?> href="/<?php echo $file; ?>">
                        <img src="/images/<?php echo $image; ?>" alt="">
                        <span><?php echo $label; ?></span>
                    </a>
                </li>
            <?php endforeach; ?>
        </ul>
    </nav>
<?php endforeach; ?>

このコードでやっていることは、大きく分けると次の3つです。

  • 1つ目は、メニューの中身(見出し、ページ、表示名、画像)を、ひとつの「配列」にまとめて書いていること。
  • 2つ目は、その配列を「foreach」でくり返し取り出して、HTMLを自動で作っていること。
  • 3つ目は、今見ているページのリンクにだけ、目印のクラスを付けていること。

それぞれ見ていきましょう。

2. 配列ってなに?(メニューの中身をまとめて書く)

配列は、いくつものデータを1つの箱にまとめて入れておける仕組みです。PHPでは [ ] (角かっこ)で書きます。

いちばんシンプルな配列はこんな形です。

$fruits = ['りんご', 'みかん', 'ぶどう'];

これだと、中身に「名前」が付いていません。

そこで、「名前 => 中身」の形で書くと、名前付きの配列になります。これを「連想配列」と呼びます。

$prices = [
'コーヒー' => 400,
'ケーキ' => 500,
];

この場合、「コーヒー」という名前(キー)で、400という値を取り出せます。

今回のコードでは、この連想配列を何段も重ねて(入れ子にして)使っています。ばらして見るとこうなります。

  • いちばん外側の名前は、グループの見出しです(「お店について」「メニュー」)。
  • その中身は [アイコン名, ページの一覧] という2つセットになっています。
  • ページの一覧は、「ファイル名 => [表示名, 画像名]」の連想配列です。

文章にすると少しややこしいですが、

「見出しごとに、アイコンとページの一覧がある。ページごとに、表示名と画像がある」

と考えるとわかりやすいです。

この書き方のいいところは、メニューを1つ増やしたいときに、配列に1行足すだけで済むことです。

たとえば「ランチ」のページを増やすなら、

‘lunch.php’ => [‘ランチ’, ‘lunch.jpg’],

を「メニュー」グループの中に足すだけで、リンクも画像も自動で表示されます。

HTMLを何行もコピーして書き換える必要がありません。

3. foreach でくり返す(しかもHTMLと混ぜやすい書き方)

配列に入れたデータを1つずつ取り出すのが foreach です。基本の形はこうです。

foreach ($prices as $name => $price) {
  echo $name . 'は' . $price . '円です';
}

$prices の中身を上から順番に取り出して、名前を $name に、値を $price に入れながら、{ } の中の処理をくり返します。

ここで、今回のコードをもう一度見てみると、{ } ではなく、こんな書き方になっています。

<?php foreach ($menus as $heading => [$headingIcon, $links]): ?>
    (ここにHTML)
<?php endforeach; ?>

これは「foreach の別の書き方(オルタナティブ構文)」と呼ばれるものです。

{ の代わりに「:」(コロン)を書き、} の代わりに「endforeach;」で終わらせます。

なぜわざわざこう書くのかというと、HTMLの中に書くときに読みやすいからです。

{ } で書くと、HTMLの途中に } だけがぽつんと残って、「これは何の終わり?」とわかりにくくなります

endforeach と書いてあれば、「ここで foreach が終わるんだな」とひと目でわかります。

同じように、if にも別の書き方があります。

<?php if (条件): ?>
    条件に合うときだけ表示するHTML
<?php endif; ?>

今回のコードでは、この if を使って「今見ているページのときだけ class を付ける」ということをしています(5章で説明します)。

4. [$label, $image] ってなに?(取り出しと同時に分ける)

foreach の行に、こんな部分がありました。

foreach ($links as $file => [$label, $image])

ふつうなら「$file => $value」のように、値を1つの変数で受け取ります。

ところが今回の値は [‘お店の紹介’, ‘about.jpg’] のように、2つセットになっています。

そこで、受け取る側も [$label, $image] と書いておくと、セットの1つ目が $label に、2つ目が $image に、自動で分けて入ります。

これを「分割代入」と呼びます(PHP 7.1以降で使える書き方です)。

分割代入を使わないと、こう書くことになります。

foreach ($links as $file => $value) {
 $label = $value[0];
 $image = $value[1];
}

結果は同じですが、分割代入を使うと1行で済み、何が入っているのかも名前でわかるので読みやすくなります。

5. 今見ているページを見分ける

サイドバーのメニューでは、「今このページを見ています」とわかるように、今のページのリンクだけ色を変えたいことがよくあります。それをしているのが、いちばん上のこの1行です。

$current = basename($_SERVER['SCRIPT_NAME']);

$_SERVER['SCRIPT_NAME'] には、今動いているPHPファイルの場所が入っています。
たとえば「/shop/about.php」のような形です。

basename() は、その中から最後のファイル名の部分だけを取り出す関数です。
「/shop/about.php」なら「about.php」だけが取り出されます。

あとは、メニューのファイル名と比べるだけです。

<a<?php if ($file === $current): ?> class="is-current"<?php endif; ?> href="...">

メニューのファイル名($file)と今のページ($current)が同じときだけ、class=”is-current” が付きます。

CSSで .is-current に色や枠を付けておけば、今いるページだけ目立たせられます。

ちなみに「===」は、「中身も種類もまったく同じか」を比べる書き方です。
「==」でも動くことが多いですが、思わぬ一致を防ぐために「===」を使うのがおすすめです。

さらに、読み上げソフトを使う方にも「今のページ」を伝えたい場合は、class と一緒に aria-current=”page” という属性を付けておくと親切です。

6. いろいろなページで使い回す(include)

このサイドバーは、1つのページだけでなく、サイトのいろいろなページに表示したいものです。そこで、このコードを side.php のような別のファイルに保存しておき、表示したいページで読み込みます。

<?php include 'side.php'; ?>

include は、「指定したファイルの中身を、この場所に入れる」という命令です。こうしておけば、メニューを直したいときは side.php を1か所直すだけで、全部のページに反映されます。

しかも、5章の「今のページを見分ける」仕組みがあるので、同じ side.php を読み込んでいても、ページごとに正しい項目が自動で目立つようになります。

7. 注意したいこと(echo とセキュリティ)

今回のコードでは、<?php echo $label; ?> のように、配列の中身をそのまま画面に出しています。

これは、配列の中身を自分で書いた決まった文字だから大丈夫です。

ただし、フォームに入力された文字やURLの一部など、外から来た文字を表示するときは、そのまま echo してはいけません。

悪意のあるHTMLやスクリプトが混ざっていると、それがそのまま動いてしまうからです。

外から来た文字を表示するときは、

<?php echo htmlspecialchars($text, ENT_QUOTES, 'UTF-8'); ?>

のように htmlspecialchars() を通して、HTMLとして動かない形に変えてから表示しましょう。

まとめ

今回の書き方のポイントをまとめると、次のとおりです。

  • メニューの中身は、配列にまとめて書いておく。増やしたいときは1行足すだけ。
  • foreach の「:」と「endforeach;」を使うと、HTMLの中でも読みやすく書ける。
  • [$label, $image] のように書くと、取り出したセットを自動で分けられる。
  • basename($_SERVER[‘SCRIPT_NAME’]) で今のファイル名を取り出し、メニューと比べれば、今いるページを目立たせられる。
  • include で別ファイルにしておけば、1か所直すだけで全ページに反映される。

最初は記号が多くて難しく見えますが、ひとつずつ分けて見ると、どれも「同じことを何度も書かないための工夫」だとわかります。同じようなHTMLを何回もコピーしているな、と感じたら、ぜひ配列と foreach を試してみてください。

最後まで読んでいただき、ありがとうございました。