如何用 PHP 动态按字母分组并双列展示歌曲列表(零重复代码)

1次阅读

如何用 PHP 动态按字母分组并双列展示歌曲列表(零重复代码)

本文介绍一种高效、可维护的 php 实现方案:仅一次数据库查询,将歌曲按首字母自动分组,并均分为左右两列(每列最多 13 个字母),彻底避免为 a–z 重复书写 26 次 sql 和模板逻辑。

本文介绍一种高效、可维护的 php 实现方案:仅一次数据库查询,将歌曲按首字母自动分组,并均分为左右两列(每列最多 13 个字母),彻底避免为 a–z 重复书写 26 次 sql 和模板逻辑。

在构建歌单类应用(如在线吉他谱库、合唱曲目索引页)时,常需将大量歌曲按标题首字母归类,并以双栏布局呈现——左栏 A–M,右栏 N–Z。若采用原始思路:为每个字母单独写一条 WHERE title LIKE ‘A%’ 查询 + 单独变量 $songTitleA, $songTitleB……不仅代码冗长难维护,还极易因拼写错误或遗漏导致某字母数据丢失,更违背“DRY(Don’t Repeat Yourself)”原则。

以下方案完全重构流程,核心思想是 “一次查询、内存分组、结构化渲染”,兼顾性能、可读性与扩展性:

✅ 步骤一:单次查询获取全部有序数据

<?php require_once 'config.php';  // ✅ 关键优化:只执行一次查询,按标题升序排列 $sql = "SELECT id, title, chord FROM song ORDER BY title ASC"; $stmt = $conn->prepare($sql); $stmt->execute(); $songs = $stmt->fetchAll(PDO::FETCH_ASSOC); ?>

⚠️ 注意:确保 title 字段无前导空格或不可见字符(可加 TRIM() 或在入库时清洗)。若需兼容大小写混合(如“a Song”),建议统一转大写后再取首字母:strtoupper($song[‘title’][0])。

✅ 步骤二:内存中按首字母动态分组

<?php $grouped = [];  foreach ($songs as $song) {// 安全提取首字母(处理空标题 / 非字母开头)$firstChar = !empty($song['title']) ? strtoupper($song['title'][0]) : '#';     // 过滤非字母字符(如数字、符号),归入 '#' 组(可后续单独处理)$letter = ctype_alpha($firstChar) ? $firstChar : '#';      $grouped[$letter][] = $song;}  // 按字母顺序排序分组键(确保 A, B, C…… 显示顺序正确)ksort($grouped); ?>

✅ 步骤三:均分两栏(按字母数量,非歌曲数)

<?php // 将字母分组数组切分为左右两部分:左栏最多 13 个字母,右栏余下 $midpoint = (int) ceil(count($grouped) / 2); $columns = array_chunk($grouped, $midpoint, true); $leftColumn = $columns[0] ?? []; $rightColumn = $columns[1] ?? []; ?>

? 说明:array_chunk(…, true) 保留键名(即字母),确保 [‘A’ => […], ‘B’ => […]] 结构不丢失;ceil() 保证当总字母数为奇数(如 25)时,左栏多 1 个(13 vs 12),符合常见排版习惯。

立即学习 PHP 免费学习笔记(深入)”;

✅ 步骤四:封装可复用的渲染函数

<?php function renderColumn(array $lettersGroup, string $columnClass = 'column'): string {$html = "<div class="{$columnClass}">n";     $html .= "  <div class="table-wrapper">n";     $html .= "    <table class="fl-table">n";      foreach ($lettersGroup as $letter => $songs) {// 表头:字母 + 空白占位列         $html .= "      <tr>n";         $html .= "        <th style="color:black; width:80%">{$letter}</th>n";         $html .= "        <th style="color:white;"></th>n";         $html .= "      </tr>n";          // 歌曲行:标题 + 和弦(带详情链接)foreach ($songs as $song) {$html .= "      <tr>n";             $html .= "        <td><a style="margin-left:10px" href="details.php?id={$song['id']}">{$song['title']}</a></td>n";             $html .= "        <td><span style="margin-left:10px">{$song['chord']}</span></td>n";             $html .= "      </tr>n";         }     }      $html .= "    </table>n";     $html .= "  </div>n";     $html .= "</div>n";     return $html; } ?>

✅ 步骤五:最终输出(简洁、无重复)

<div class="song-columns">   <?= renderColumn($leftColumn, 'column left') ?>   <?= renderColumn($rightColumn, 'column right') ?> </div>

? 进阶提示与注意事项

  • 性能友好 :全程无 N+1 查询,仅 1 次 DB 请求 + PHP 内存操作,即使千级歌曲也毫秒级响应。
  • 健壮性增强 :对空标题、数字开头(如“1999”)、特殊符号(如“& Band”)做了归类处理,避免键名错误。
  • 样式解耦 :HTML 结构与业务逻辑分离,CSS 可通过 .left / .right 独立控制宽度、间距、响应式断点。
  • 扩展灵活 :如需改为三栏、按歌曲数均分、或添加“# 其他”汇总栏,只需调整 array_chunk 参数或预处理 $grouped 数组。
  • 安全加固 :实际生产环境务必对 $song[‘title’] 和 $song[‘chord’] 做 htmlspecialchars() 转义,防止 XSS:
    htmlspecialchars($song['title'], ENT_QUOTES, 'UTF-8')

此方案将原本 26×(SQL + 变量 + 循环)的硬编码,压缩为 4 个清晰逻辑块,代码量减少 80% 以上,且具备自解释性与长期可维护性——这才是现代 PHP Web 开发应有的工程实践。

星耀云
版权声明:本站原创文章,由 星耀云 2026-03-22发表,共计2631字。
转载说明:转载本网站任何内容,请按照转载方式正确书写本站原文地址。本站提供的一切软件、教程和内容信息仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。
text=ZqhQzanResources