[PHP]range関数の使い方を徹底解説!連続した値の配列生成をマスター

PHP

PHPでループ処理や連続したデータを扱う際、1から10までの数値配列やアルファベット順の配列が必要になることがよくあります。この記事では、PHPのrange関数について、基本的な使い方から実践的な活用方法まで詳しく解説していきます。

range関数とは?

rangeは、指定した範囲の連続した値を含む配列を生成する関数です。数値の連番だけでなく、文字の連番も生成できます。

基本的な構文

array range(mixed $start, mixed $end, int|float $step = 1)

パラメータ:

  • $start: 開始値
  • $end: 終了値
  • $step: ステップ(増減の幅)デフォルトは1

戻り値:

  • 開始値から終了値までの連続した値を含む配列

基本的な使い方

数値の連番配列

<?php
// 1から10までの配列
$numbers = range(1, 10);
print_r($numbers);
// Array ( [0] => 1 [1] => 2 ... [9] => 10 )

// 0から5までの配列
$numbers = range(0, 5);
print_r($numbers);
// Array ( [0] => 0 [1] => 1 ... [5] => 5 )

// 降順(10から1まで)
$numbers = range(10, 1);
print_r($numbers);
// Array ( [0] => 10 [1] => 9 ... [9] => 1 )

// 負の数を含む範囲
$numbers = range(-5, 5);
print_r($numbers);
// Array ( [0] => -5 [1] => -4 ... [10] => 5 )
?>

ステップを指定

<?php
// 0から10まで2刻み
$evens = range(0, 10, 2);
print_r($evens);
// Array ( [0] => 0 [1] => 2 [2] => 4 [3] => 6 [4] => 8 [5] => 10 )

// 1から10まで2刻み(奇数)
$odds = range(1, 10, 2);
print_r($odds);
// Array ( [0] => 1 [1] => 3 [2] => 5 [3] => 7 [4] => 9 )

// 小数のステップ
$decimals = range(0, 1, 0.25);
print_r($decimals);
// Array ( [0] => 0 [1] => 0.25 [2] => 0.5 [3] => 0.75 [4] => 1 )

// 大きなステップ
$tens = range(0, 100, 10);
print_r($tens);
// Array ( [0] => 0 [1] => 10 [2] => 20 ... [10] => 100 )
?>

文字の連番

<?php
// アルファベット小文字
$alphabet = range('a', 'z');
print_r($alphabet);
// Array ( [0] => a [1] => b ... [25] => z )

// アルファベット大文字
$uppercase = range('A', 'Z');
print_r($uppercase);

// 部分的な範囲
$partial = range('a', 'f');
print_r($partial);
// Array ( [0] => a [1] => b [2] => c [3] => d [4] => e [5] => f )

// 降順
$reverse = range('z', 'a');
print_r($reverse);
// Array ( [0] => z [1] => y ... [25] => a )
?>

実践的な使用例

1. ループ処理の簡素化

<?php
/**
 * rangeを使ったループ処理
 */

// 従来の方法
echo "=== 従来のforループ ===\n";
for ($i = 1; $i <= 5; $i++) {
    echo "回数: {$i}\n";
}

// rangeを使った方法
echo "\n=== rangeを使用 ===\n";
foreach (range(1, 5) as $i) {
    echo "回数: {$i}\n";
}

// 複雑な処理
echo "\n=== 年齢グループ処理 ===\n";
foreach (range(0, 100, 10) as $age) {
    echo "{$age}〜" . ($age + 9) . "歳: ";
    
    if ($age < 20) {
        echo "未成年\n";
    } elseif ($age < 65) {
        echo "成人\n";
    } else {
        echo "高齢者\n";
    }
}

// 年のリストを生成
echo "\n=== 年のセレクトボックス ===\n";
$currentYear = date('Y');
$years = range($currentYear, $currentYear - 100);

echo "<select name='birth_year'>\n";
foreach ($years as $year) {
    echo "  <option value='{$year}'>{$year}年</option>\n";
}
echo "</select>\n";
?>

2. ページネーション

<?php
/**
 * ページネーションクラス
 */
class Pagination {
    private $totalItems;
    private $itemsPerPage;
    private $currentPage;
    
    public function __construct($totalItems, $itemsPerPage = 10, $currentPage = 1) {
        $this->totalItems = $totalItems;
        $this->itemsPerPage = $itemsPerPage;
        $this->currentPage = max(1, $currentPage);
    }
    
    /**
     * 総ページ数を取得
     */
    public function getTotalPages() {
        return ceil($this->totalItems / $this->itemsPerPage);
    }
    
    /**
     * ページ番号のリストを取得
     */
    public function getPageNumbers($visiblePages = 5) {
        $totalPages = $this->getTotalPages();
        
        if ($totalPages <= $visiblePages) {
            return range(1, $totalPages);
        }
        
        $half = floor($visiblePages / 2);
        $start = max(1, $this->currentPage - $half);
        $end = min($totalPages, $start + $visiblePages - 1);
        
        // 終端に達した場合、開始位置を調整
        if ($end - $start + 1 < $visiblePages) {
            $start = max(1, $end - $visiblePages + 1);
        }
        
        return range($start, $end);
    }
    
    /**
     * HTMLを生成
     */
    public function render($baseUrl = '?page=') {
        $html = '<div class="pagination">';
        
        // 前へ
        if ($this->currentPage > 1) {
            $prevPage = $this->currentPage - 1;
            $html .= "<a href='{$baseUrl}{$prevPage}' class='prev'>« 前へ</a>";
        }
        
        // ページ番号
        foreach ($this->getPageNumbers() as $page) {
            $activeClass = ($page === $this->currentPage) ? ' active' : '';
            $html .= "<a href='{$baseUrl}{$page}' class='page{$activeClass}'>{$page}</a>";
        }
        
        // 次へ
        if ($this->currentPage < $this->getTotalPages()) {
            $nextPage = $this->currentPage + 1;
            $html .= "<a href='{$baseUrl}{$nextPage}' class='next'>次へ »</a>";
        }
        
        $html .= '</div>';
        
        return $html;
    }
    
    /**
     * 現在のページのアイテムのオフセットを取得
     */
    public function getOffset() {
        return ($this->currentPage - 1) * $this->itemsPerPage;
    }
    
    /**
     * 現在のページの情報テキストを取得
     */
    public function getInfoText() {
        $start = $this->getOffset() + 1;
        $end = min($this->getOffset() + $this->itemsPerPage, $this->totalItems);
        
        return "{$this->totalItems}件中 {$start}〜{$end}件を表示";
    }
}

// 使用例
echo "=== ページネーション ===\n";
$pagination = new Pagination(250, 10, 5);

echo $pagination->getInfoText() . "\n";
echo "総ページ数: " . $pagination->getTotalPages() . "\n";
echo "表示するページ番号: " . implode(', ', $pagination->getPageNumbers()) . "\n\n";

echo $pagination->render() . "\n";
?>

3. カレンダー生成

<?php
/**
 * カレンダー生成クラス
 */
class CalendarGenerator {
    
    /**
     * 月のカレンダーを生成
     */
    public static function generateMonth($year, $month) {
        $firstDay = mktime(0, 0, 0, $month, 1, $year);
        $daysInMonth = date('t', $firstDay);
        $dayOfWeek = date('w', $firstDay);
        
        $calendar = [];
        $calendar['year'] = $year;
        $calendar['month'] = $month;
        $calendar['month_name'] = date('Y年n月', $firstDay);
        $calendar['weeks'] = [];
        
        $week = array_fill(0, 7, null);
        
        // 日付を配置
        foreach (range(1, $daysInMonth) as $day) {
            $currentDayOfWeek = ($dayOfWeek + $day - 1) % 7;
            $week[$currentDayOfWeek] = $day;
            
            // 土曜日または月末で週を追加
            if ($currentDayOfWeek === 6 || $day === $daysInMonth) {
                $calendar['weeks'][] = $week;
                $week = array_fill(0, 7, null);
            }
        }
        
        return $calendar;
    }
    
    /**
     * HTMLテーブルとして出力
     */
    public static function renderHtml($year, $month) {
        $calendar = self::generateMonth($year, $month);
        $weekdays = ['日', '月', '火', '水', '木', '金', '土'];
        
        $html = "<div class='calendar'>\n";
        $html .= "<h2>{$calendar['month_name']}</h2>\n";
        $html .= "<table>\n";
        
        // ヘッダー
        $html .= "<thead>\n<tr>\n";
        foreach ($weekdays as $day) {
            $html .= "<th>{$day}</th>\n";
        }
        $html .= "</tr>\n</thead>\n";
        
        // 日付
        $html .= "<tbody>\n";
        foreach ($calendar['weeks'] as $week) {
            $html .= "<tr>\n";
            foreach ($week as $i => $day) {
                $class = '';
                if ($i === 0) $class = 'sunday';
                if ($i === 6) $class = 'saturday';
                
                $dayText = $day !== null ? $day : '';
                $html .= "<td class='{$class}'>{$dayText}</td>\n";
            }
            $html .= "</tr>\n";
        }
        $html .= "</tbody>\n";
        $html .= "</table>\n";
        $html .= "</div>\n";
        
        return $html;
    }
    
    /**
     * 年間カレンダーを生成
     */
    public static function generateYear($year) {
        $months = [];
        
        foreach (range(1, 12) as $month) {
            $months[] = self::generateMonth($year, $month);
        }
        
        return $months;
    }
}

// 使用例
echo "=== カレンダー生成 ===\n";
echo CalendarGenerator::renderHtml(2024, 12);

echo "\n=== 年間の月リスト ===\n";
$yearCalendars = CalendarGenerator::generateYear(2024);
foreach ($yearCalendars as $cal) {
    echo "{$cal['month_name']}: {$cal['weeks'][0][0]}日〜最終日\n";
}
?>

4. データ生成とテスト

<?php
/**
 * テストデータ生成クラス
 */
class TestDataGenerator {
    
    /**
     * ダミーユーザーを生成
     */
    public static function generateUsers($count) {
        $users = [];
        
        foreach (range(1, $count) as $id) {
            $users[] = [
                'id' => $id,
                'username' => 'user' . str_pad($id, 4, '0', STR_PAD_LEFT),
                'email' => "user{$id}@example.com",
                'created_at' => date('Y-m-d', strtotime("-{$id} days"))
            ];
        }
        
        return $users;
    }
    
    /**
     * 売上データを生成
     */
    public static function generateSalesData($year, $month) {
        $daysInMonth = date('t', mktime(0, 0, 0, $month, 1, $year));
        $salesData = [];
        
        foreach (range(1, $daysInMonth) as $day) {
            $date = sprintf('%04d-%02d-%02d', $year, $month, $day);
            $salesData[] = [
                'date' => $date,
                'sales' => rand(10000, 100000),
                'orders' => rand(10, 100),
                'customers' => rand(5, 50)
            ];
        }
        
        return $salesData;
    }
    
    /**
     * アルファベットの選択肢を生成
     */
    public static function generateOptions($type = 'uppercase') {
        switch ($type) {
            case 'uppercase':
                return range('A', 'Z');
            case 'lowercase':
                return range('a', 'z');
            case 'numeric':
                return range(1, 26);
            default:
                return range('A', 'Z');
        }
    }
    
    /**
     * 時間のオプションを生成
     */
    public static function generateTimeOptions($startHour = 0, $endHour = 23, $interval = 30) {
        $times = [];
        
        foreach (range($startHour, $endHour) as $hour) {
            foreach (range(0, 60 - $interval, $interval) as $minute) {
                $times[] = sprintf('%02d:%02d', $hour, $minute);
            }
        }
        
        return $times;
    }
    
    /**
     * 価格帯のオプションを生成
     */
    public static function generatePriceRanges($min = 0, $max = 100000, $step = 10000) {
        $ranges = [];
        
        foreach (range($min, $max - $step, $step) as $lower) {
            $upper = $lower + $step;
            $ranges[] = [
                'label' => number_format($lower) . '円〜' . number_format($upper) . '円',
                'min' => $lower,
                'max' => $upper
            ];
        }
        
        return $ranges;
    }
}

// 使用例
echo "=== テストユーザー生成 ===\n";
$users = TestDataGenerator::generateUsers(5);
foreach ($users as $user) {
    echo "{$user['id']}: {$user['username']} ({$user['email']}) - 登録日: {$user['created_at']}\n";
}

echo "\n=== 売上データ生成 ===\n";
$sales = TestDataGenerator::generateSalesData(2024, 1);
echo "1月の売上データ: " . count($sales) . "日分\n";
echo "最初の3日:\n";
foreach (array_slice($sales, 0, 3) as $data) {
    echo "  {$data['date']}: 売上¥" . number_format($data['sales']) . " 注文数{$data['orders']}\n";
}

echo "\n=== アルファベット選択肢 ===\n";
echo "大文字: " . implode(', ', TestDataGenerator::generateOptions('uppercase')) . "\n";

echo "\n=== 時間オプション(営業時間9:00-18:00、30分刻み) ===\n";
$times = TestDataGenerator::generateTimeOptions(9, 18, 30);
echo implode(', ', $times) . "\n";

echo "\n=== 価格帯オプション ===\n";
$priceRanges = TestDataGenerator::generatePriceRanges(0, 50000, 10000);
foreach ($priceRanges as $range) {
    echo "{$range['label']}\n";
}
?>

5. グラフデータの生成

<?php
/**
 * チャートデータ生成クラス
 */
class ChartDataGenerator {
    
    /**
     * 折れ線グラフのデータを生成
     */
    public static function generateLineChartData($points = 12) {
        $labels = [];
        $data = [];
        
        foreach (range(1, $points) as $i) {
            $labels[] = "{$i}月";
            $data[] = rand(10, 100);
        }
        
        return [
            'labels' => $labels,
            'datasets' => [
                [
                    'label' => '売上',
                    'data' => $data
                ]
            ]
        ];
    }
    
    /**
     * 棒グラフのデータを生成(年齢層別)
     */
    public static function generateBarChartData() {
        $ageGroups = [];
        $counts = [];
        
        foreach (range(10, 60, 10) as $age) {
            $ageGroups[] = "{$age}代";
            $counts[] = rand(50, 500);
        }
        
        return [
            'labels' => $ageGroups,
            'datasets' => [
                [
                    'label' => 'ユーザー数',
                    'data' => $counts
                ]
            ]
        ];
    }
    
    /**
     * ヒートマップデータを生成(時間×曜日)
     */
    public static function generateHeatmapData() {
        $weekdays = ['月', '火', '水', '木', '金', '土', '日'];
        $hours = range(0, 23);
        $data = [];
        
        foreach ($weekdays as $day) {
            $dayData = [];
            foreach ($hours as $hour) {
                $dayData[] = [
                    'hour' => $hour,
                    'value' => rand(0, 100)
                ];
            }
            $data[$day] = $dayData;
        }
        
        return [
            'weekdays' => $weekdays,
            'hours' => $hours,
            'data' => $data
        ];
    }
    
    /**
     * SVG棒グラフを生成
     */
    public static function renderBarChart($data, $width = 600, $height = 400) {
        $maxValue = max($data);
        $barWidth = ($width - 100) / count($data);
        $scale = ($height - 100) / $maxValue;
        
        $svg = sprintf('<svg width="%d" height="%d" xmlns="http://www.w3.org/2000/svg">', $width, $height);
        $svg .= '<rect width="' . $width . '" height="' . $height . '" fill="#f9f9f9"/>';
        
        foreach ($data as $i => $value) {
            $barHeight = $value * $scale;
            $x = 50 + $i * $barWidth;
            $y = $height - 50 - $barHeight;
            
            // 棒
            $svg .= sprintf(
                '<rect x="%f" y="%f" width="%f" height="%f" fill="#4285f4"/>',
                $x,
                $y,
                $barWidth * 0.8,
                $barHeight
            );
            
            // 値のラベル
            $svg .= sprintf(
                '<text x="%f" y="%f" text-anchor="middle" font-size="12">%d</text>',
                $x + $barWidth * 0.4,
                $y - 5,
                $value
            );
            
            // X軸ラベル
            $svg .= sprintf(
                '<text x="%f" y="%f" text-anchor="middle" font-size="12">%d</text>',
                $x + $barWidth * 0.4,
                $height - 30,
                $i + 1
            );
        }
        
        // X軸
        $svg .= sprintf(
            '<line x1="50" y1="%d" x2="%d" y2="%d" stroke="black" stroke-width="2"/>',
            $height - 50,
            $width - 50,
            $height - 50
        );
        
        // Y軸
        $svg .= sprintf(
            '<line x1="50" y1="50" x2="50" y2="%d" stroke="black" stroke-width="2"/>',
            $height - 50
        );
        
        $svg .= '</svg>';
        
        return $svg;
    }
}

// 使用例
echo "=== 折れ線グラフデータ ===\n";
$lineData = ChartDataGenerator::generateLineChartData(12);
echo "ラベル: " . implode(', ', $lineData['labels']) . "\n";
echo "データ: " . implode(', ', $lineData['datasets'][0]['data']) . "\n\n";

echo "=== 棒グラフデータ ===\n";
$barData = ChartDataGenerator::generateBarChartData();
foreach ($barData['labels'] as $i => $label) {
    $value = $barData['datasets'][0]['data'][$i];
    echo "{$label}: {$value}\n";
}

echo "\n=== SVG棒グラフ ===\n";
$data = range(10, 100, 10);
echo ChartDataGenerator::renderBarChart($data);

echo "\n\n=== ヒートマップデータ ===\n";
$heatmap = ChartDataGenerator::generateHeatmapData();
echo "曜日: " . implode(', ', $heatmap['weekdays']) . "\n";
echo "時間帯: " . count($heatmap['hours']) . "時間分\n";
?>

よくある間違いと注意点

間違い1: 大きすぎる範囲でメモリ不足

<?php
// ❌ メモリ不足の危険性
$huge = range(1, 10000000); // 1000万要素の配列

// ✅ 大きな範囲にはジェネレータを使用
function generateRange($start, $end, $step = 1) {
    for ($i = $start; $i <= $end; $i += $step) {
        yield $i;
    }
}

foreach (generateRange(1, 10000000) as $num) {
    // メモリ効率的に処理
}
?>

間違い2: ステップの符号が逆

<?php
// ❌ 増加範囲に負のステップ
$wrong = range(1, 10, -1); // 空の配列

// ✅ 降順には負のステップ、または順序を逆に
$correct1 = range(10, 1, -1);
$correct2 = range(10, 1); // ステップ省略可
?>

間違い3: 浮動小数点の精度問題

<?php
// 浮動小数点の精度に注意
$decimals = range(0, 1, 0.1);
print_r($decimals);
// 期待: 11要素 (0, 0.1, 0.2, ..., 1.0)
// 実際: 浮動小数点誤差で予期しない結果の可能性

// ✅ 整数で計算してから変換
$safe = [];
foreach (range(0, 10) as $i) {
    $safe[] = $i / 10;
}
?>

まとめ

range関数は、PHPで連続した値の配列を生成するための便利な関数です。以下のポイントを押さえておきましょう。

  • 数値と文字の連番配列を簡単に生成
  • ステップ指定で間隔を制御可能
  • 昇順・降順どちらも対応
  • ループ処理の簡素化に活用
  • ページネーション、カレンダー、テストデータ生成に便利
  • 大きな範囲にはジェネレータの使用を検討
  • 浮動小数点の精度問題に注意
  • foreachと組み合わせて可読性の高いコードを実現

rangeを使いこなすことで、ループ処理やデータ生成が直感的で読みやすいコードになります。適切に活用して、効率的なPHPプログラミングを実現しましょう!

タイトルとURLをコピーしました