array_chunk() 函数是PHP中用于将数组分割成多个小块数组的实用函数。它在处理大型数据集、分页显示、批量操作等场景中非常有用。
array_chunk() 函数用于将一个数组分割成多个包含指定数量元素的子数组。这在处理大型数组时特别有用,可以避免内存溢出问题,并支持分批次处理数据。
array_chunk(array, size, preserve_keys);
| 参数 | 描述 |
|---|---|
| array | 必需。规定要分割的数组。 |
| size | 必需。一个整数,规定每个新数组块包含多少个元素。必须是大于0的整数。 |
| preserve_keys | 可选。规定是否保留原始数组的键名:
|
演示如何使用 array_chunk() 进行基本的数组分割。
<?php
// 创建一个数值数组
$numbers = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
echo "原始数组:";
print_r($numbers);
// 将数组分割成每块3个元素
$chunks = array_chunk($numbers, 3);
echo "分割后的数组块(每块3个元素):";
print_r($chunks);
// 输出说明:
// 原始数组被分割成4个块: [1,2,3], [4,5,6], [7,8,9], [10]
// 最后一个块可能包含少于指定数量的元素
?>
演示如何使用 preserve_keys 参数保留原始数组的键名。
<?php
// 创建关联数组
$age = array(
"Peter" => "35",
"Ben" => "37",
"Joe" => "43",
"Harry" => "50",
"Alice" => "28",
"Bob" => "31"
);
echo "原始关联数组:";
print_r($age);
// 不保留键名(默认)
$chunks1 = array_chunk($age, 2, false);
echo "不保留键名的分割:";
print_r($chunks1);
// 保留键名
$chunks2 = array_chunk($age, 2, true);
echo "保留键名的分割:";
print_r($chunks2);
// 输出说明:
// 不保留键名:每个块使用新的数字索引 [0=>"35",1=>"37"], [0=>"43",1=>"50"], ...
// 保留键名:保持原始键名 ["Peter"=>"35","Ben"=>"37"], ["Joe"=>"43","Harry"=>"50"], ...
?>
演示如何使用 array_chunk() 实现数据分页功能。
<?php
// 模拟产品数据
$products = array();
for($i = 1; $i <= 25; $i++) {
$products[] = "产品 " . $i;
}
// 分页参数
$itemsPerPage = 5;
$currentPage = isset($_GET['page']) ? max(1, intval($_GET['page'])) : 1;
// 分割数据
$pages = array_chunk($products, $itemsPerPage);
$totalPages = count($pages);
// 获取当前页数据
if($currentPage <= $totalPages) {
$currentProducts = $pages[$currentPage - 1];
} else {
$currentProducts = array();
}
echo "=== 产品列表(第 {$currentPage} 页,共 {$totalPages} 页) ===\n";
// 显示当前页产品
foreach($currentProducts as $index => $product) {
echo ($index + 1) . ". " . $product . "\n";
}
// 生成分页链接(简化示例)
echo "\n分页导航: ";
for($page = 1; $page <= $totalPages; $page++) {
if($page == $currentPage) {
echo "[{$page}] ";
} else {
echo "{$page} ";
}
}
// 实际应用中,分页链接可能是:
// <a href="?page=1">1</a> <a href="?page=2">2</a> ...
?>
演示如何使用 array_chunk() 进行批量数据库插入操作。
<?php
// 模拟大量用户数据
$users = array();
for($i = 1; $i <= 1000; $i++) {
$users[] = array(
'username' => 'user_' . $i,
'email' => 'user' . $i . '@example.com',
'created_at' => date('Y-m-d H:i:s')
);
}
echo "总用户数: " . count($users) . "\n";
// 分批处理,每批100条记录
$batchSize = 100;
$batches = array_chunk($users, $batchSize);
echo "分割成 " . count($batches) . " 个批次,每批 {$batchSize} 条记录\n";
// 模拟批量插入
foreach($batches as $batchNumber => $batch) {
echo "处理第 " . ($batchNumber + 1) . " 批,包含 " . count($batch) . " 条记录\n";
// 在实际应用中,这里会是数据库插入操作
// 例如: $db->insertBatch('users', $batch);
// 模拟处理时间
usleep(100000); // 0.1秒延迟
}
echo "所有批次处理完成!\n";
// 实际数据库操作示例(伪代码):
/*
function batchInsertUsers($users) {
$batchSize = 100;
$batches = array_chunk($users, $batchSize);
foreach($batches as $batch) {
$placeholders = array();
$values = array();
foreach($batch as $user) {
$placeholders[] = '(?, ?, ?)';
$values[] = $user['username'];
$values[] = $user['email'];
$values[] = $user['created_at'];
}
$sql = "INSERT INTO users (username, email, created_at) VALUES " . implode(',', $placeholders);
$stmt = $pdo->prepare($sql);
$stmt->execute($values);
}
}
*/
?>
演示如何使用 array_chunk() 为网格布局准备数据。
<?php
// 图片数据
$images = array(
'image1.jpg', 'image2.jpg', 'image3.jpg', 'image4.jpg',
'image5.jpg', 'image6.jpg', 'image7.jpg', 'image8.jpg',
'image9.jpg', 'image10.jpg', 'image11.jpg', 'image12.jpg'
);
echo "=== 3列网格布局 ===\n";
// 将图片分成3列
$columns = array_chunk($images, ceil(count($images) / 3));
foreach($columns as $colIndex => $column) {
echo "第 " . ($colIndex + 1) . " 列:\n";
foreach($column as $image) {
echo " - " . $image . "\n";
}
echo "\n";
}
// 在实际的HTML输出中可能是:
/*
echo "<div class='grid-container'>";
foreach($columns as $column) {
echo "<div class='grid-column'>";
foreach($column as $image) {
echo "<img src='{$image}' alt=''>";
}
echo "</div>";
}
echo "</div>";
*/
// 响应式网格示例
function createResponsiveGrid($items, $columns) {
$chunks = array_chunk($items, ceil(count($items) / $columns));
$html = "<div class='responsive-grid'>";
foreach($chunks as $chunk) {
$html .= "<div class='grid-column'>";
foreach($chunk as $item) {
$html .= "<div class='grid-item'>{$item}</div>";
}
$html .= "</div>";
}
$html .= "</div>";
return $html;
}
// 使用示例
$items = array('项目1', '项目2', '项目3', '项目4', '项目5', '项目6');
echo createResponsiveGrid($items, 2);
?>
演示如何处理最后一个不完整的块,以及如何确保每个块的大小一致。
<?php
// 方法1: 使用 array_pad 填充不完整块
function chunkWithPadding($array, $size, $padValue = null) {
$chunks = array_chunk($array, $size);
// 填充最后一个块
$lastChunk = end($chunks);
if(count($lastChunk) < $size) {
$chunks[count($chunks) - 1] = array_pad($lastChunk, $size, $padValue);
}
return $chunks;
}
$data = array(1, 2, 3, 4, 5, 6, 7);
echo "原始数据: ";
print_r($data);
$paddedChunks = chunkWithPadding($data, 3, '空位');
echo "填充后的分块: ";
print_r($paddedChunks);
// 方法2: 确保每个块大小完全一致(可能丢失数据)
function chunkExact($array, $size) {
$total = count($array);
$completeChunks = floor($total / $size);
$result = array();
for($i = 0; $i < $completeChunks; $i++) {
$result[] = array_slice($array, $i * $size, $size);
}
return $result;
}
$exactChunks = chunkExact($data, 3);
echo "精确分块(丢弃不完整块): ";
print_r($exactChunks);
// 方法3: 循环分块(适用于流式处理)
function chunkCircular($array, $size) {
$result = array();
$length = count($array);
for($i = 0; $i < $length; $i += $size) {
$result[] = array_slice($array, $i, $size);
}
return $result;
}
$circularChunks = chunkCircular($data, 3);
echo "循环分块结果: ";
print_r($circularChunks);
?>
演示如何处理多维数组的分块需求。
<?php
// 多维数组数据
$students = array(
array('name' => '张三', 'score' => 85),
array('name' => '李四', 'score' => 92),
array('name' => '王五', 'score' => 78),
array('name' => '赵六', 'score' => 88),
array('name' => '钱七', 'score' => 95),
array('name' => '孙八', 'score' => 82)
);
echo "原始学生数据:";
print_r($students);
// 按每2个学生一组分块
$groups = array_chunk($students, 2);
echo "分组后的学生数据(每组2人):";
print_r($groups);
// 处理分组数据
foreach($groups as $groupIndex => $group) {
echo "第 " . ($groupIndex + 1) . " 组:\n";
$totalScore = 0;
foreach($group as $student) {
echo " - " . $student['name'] . ": " . $student['score'] . "分\n";
$totalScore += $student['score'];
}
$average = $totalScore / count($group);
echo " 平均分: " . round($average, 2) . "分\n\n";
}
// 复杂数据结构分块
$complexData = array(
'group1' => array('a', 'b', 'c', 'd'),
'group2' => array('e', 'f', 'g', 'h', 'i'),
'group3' => array('j', 'k')
);
// 先将所有数据合并,再分块
$allItems = array();
foreach($complexData as $group => $items) {
$allItems = array_merge($allItems, $items);
}
$chunkedItems = array_chunk($allItems, 3);
echo "合并后分块的结果:";
print_r($chunkedItems);
?>
| 返回值: | 返回一个多维数组,包含分割后的数组块。如果 size 小于1,则返回 NULL 并抛出 E_WARNING 错误。 |
|---|---|
| PHP 版本: | 4.2+ |
| 更新日志: |
|
<?php
/**
* 安全的分块函数,包含参数验证
*/
function safe_array_chunk($array, $size, $preserve_keys = false) {
// 参数验证
if(!is_array($array)) {
throw new InvalidArgumentException('第一个参数必须是数组');
}
if(!is_int($size) || $size < 1) {
throw new InvalidArgumentException('size参数必须是大于0的整数');
}
if(empty($array)) {
return array();
}
return array_chunk($array, $size, $preserve_keys);
}
/**
* 使用生成器处理大型数组的分块(节省内存)
*/
function array_chunk_generator($array, $size) {
$total = count($array);
for($i = 0; $i < $total; $i += $size) {
yield array_slice($array, $i, $size);
}
}
/**
* 分块处理并执行回调函数
*/
function process_in_chunks($array, $size, callable $callback) {
$chunks = array_chunk($array, $size);
$results = array();
foreach($chunks as $chunkIndex => $chunk) {
$results[] = $callback($chunk, $chunkIndex);
}
return $results;
}
// 使用示例
try {
$data = range(1, 100);
// 使用安全分块
$chunks = safe_array_chunk($data, 10);
echo "安全分块结果,共 " . count($chunks) . " 个块\n";
// 使用生成器处理大型数据
echo "使用生成器处理:\n";
foreach(array_chunk_generator($data, 10) as $index => $chunk) {
echo "处理第 " . ($index + 1) . " 块,大小: " . count($chunk) . "\n";
}
// 使用回调处理
$results = process_in_chunks($data, 10, function($chunk, $index) {
return "块{$index}的和: " . array_sum($chunk);
});
echo "回调处理结果:\n";
print_r($results);
} catch (Exception $e) {
echo "错误: " . $e->getMessage() . "\n";
}
?>
<?php
// 对于超大型数组,避免一次性加载到内存
/**
* 从文件流式读取并分块处理
*/
function processLargeFileInChunks($filename, $chunkSize, callable $processor) {
$handle = fopen($filename, 'r');
if(!$handle) {
throw new Exception("无法打开文件: {$filename}");
}
$chunk = array();
$lineNumber = 0;
while(($line = fgets($handle)) !== false) {
$chunk[] = trim($line);
$lineNumber++;
if(count($chunk) >= $chunkSize) {
$processor($chunk, $lineNumber);
$chunk = array(); // 清空块
}
}
// 处理最后的不完整块
if(!empty($chunk)) {
$processor($chunk, $lineNumber);
}
fclose($handle);
}
// 使用示例
/*
processLargeFileInChunks('large_data.txt', 1000, function($chunk, $lineNumber) {
// 处理每个块
echo "处理了 {$lineNumber} 行数据,当前块大小: " . count($chunk) . "\n";
// 这里可以是数据库插入、文件写入等操作
// 注意:在实际应用中要处理可能的错误和异常
});
*/
/**
* 使用SplFixedArray优化内存使用(对于数值数组)
*/
function chunkWithSplFixedArray($array, $size) {
$splArray = SplFixedArray::fromArray($array);
$chunkCount = ceil($splArray->count() / $size);
$result = new SplFixedArray($chunkCount);
for($i = 0; $i < $chunkCount; $i++) {
$chunk = new SplFixedArray(min($size, $splArray->count() - $i * $size));
for($j = 0; $j < $chunk->count(); $j++) {
$chunk[$j] = $splArray[$i * $size + $j];
}
$result[$i] = $chunk;
}
return $result->toArray();
}
// 性能测试示例
$largeArray = range(1, 10000);
$start = microtime(true);
$chunks1 = array_chunk($largeArray, 100);
$time1 = microtime(true) - $start;
$start = microtime(true);
$chunks2 = chunkWithSplFixedArray($largeArray, 100);
$time2 = microtime(true) - $start;
echo "array_chunk 耗时: " . round($time1, 4) . " 秒\n";
echo "SplFixedArray 分块耗时: " . round($time2, 4) . " 秒\n";
?>