使⽤phpspreadsheet导出数据时内存溢出处理
使⽤phpspreadsheet进⾏导出excel的时候遇到了内存溢出的问题,官⽅提供了的解决⽅案,官⽅⽂档中提供了APCu、redis和memcache的缓存⽅案,但是在这些缓存⽅案都需要安装相应的扩展并且都为内存型缓存,数据量⼀⼤的话就会⼤⼤占⽤系统的内存,可能会影响项⽬的正常运⾏的,于是就⾃⾏实现了⼀种⽂件缓存的⽅式,实测可以减少导excel表时⼀半的内存使⽤量,在此把代码贴在下⾯记录⼀下。
//调⽤⽰例在实例化spreadersheet对象前设置
\PhpOffice\PhpSpreadsheet\Settings::tCache(new \Excel\FileCache('/tmp/excel_cache'));
<?php
namespace Excel;
u Psr\SimpleCache\CacheInterface;
class FileCache implements CacheInterface {
const FILE_SIZE = 3000; //读取时单次缓存⾏数(⽂件分割⾏数)
private $cache_key = [];
private $cache = [], $file_handles = [], $cache_dir, $file_prefix;
private function delCacheDir($path) {
if (is_dir($path)) {
foreach (scandir($path) as $val) {
if ($val != "." && $val != "..") {
if (is_dir($path . $val)) {
$this->delCacheDir($path . $val . '/');
@rmdir($path . $val . '/');
} el {
unlink($path . $val);
}
}
}
}
}
private function getFilenameByKey($key) {
$arr = explode('.', $key);
$end = array_pop($arr);
$dir = $this->cache_dir . implode('_', $arr);
if (! is_dir($dir)) {
mkdir($dir, 0777, true);
}
新年歌曲$line = '';
$len = strlen($end);
for ($i = 0; $i < $len; $i++) {
if (is_numeric($end[$i])) {
$line .= $end[$i];
}
}
$suf = (int)round($line / lf::FILE_SIZE);
return $dir . '/' . $this->file_prefix . $suf;
}
private function getFileHandleByKey($key) {
$filename = $this->getFilenameByKey($key);
if (! array_key_exists($filename, $this->file_handles)) {
$fp = fopen($filename, 'w+');
if (! $fp) {
throw new \Exception('⽣成缓存⽂件失败');
}
$this->file_handles[$filename] = $fp;
}
return $this->file_handles[$filename];
}
public function __construct($cache_dir) {
$this->cache_dir = rtrim($cache_dir, '/') . '/';
$this->file_prefix = uniqid();
}
public function __destruct() {
public function __destruct() {
$this->clear();
日记英文}
public function clear() {
$this->cache_key = [];
foreach ($this->file_handles as $file_handle) {
ist($file_handle) && fclo($file_handle);
}
$this->delCacheDir($this->cache_dir);
return true;
}
public function delete($key) {
站长赚钱$key = $this->convertKey($key);
unt($this->cache_key[$key]);梦见小狗崽
return true;
}
public function deleteMultiple($keys) {
foreach ($keys as $key) {
$this->delete($key);
}
return true;
}
public function get($key, $default = null) {
$key = $this->convertKey($key);
if ($this->has($key)) {
$ek = $this->cache_key[$key];
if (array_key_exists($key, $this->cache) && $this->cache[$key]['ek'] == $ek) { return $this->cache[$key]['data'];
}
$fp = $this->getFileHandleByKey($key);
$this->cache = [];
fek($fp, 0);
while (! feof($fp)) {
$data = fgets($fp);
$data = json_decode(trim($data), 1);
if ($data['key'] == $key && $data['ek'] == $ek) {
$default = unrialize($data['data']);
}
$this->cache[$data['key']] = [
职业规划报告'data' => unrialize($data['data']),
'ek' => $data['ek']
];
}
}
return $default;
}
public function getMultiple($keys, $default = null) {
$results = [];
foreach ($keys as $key) {
$results[$key] = $this->get($key, $default);
}
return $results;
}
public function has($key) {
$key = $this->convertKey($key);
return array_key_exists($key, $this->cache_key);
}
public function t($key, $value, $ttl = null) {
$key = $this->convertKey($key);
if ($this->has($key) && $this->get($key) == $value) {
绿钻return true;
}
$fp = $this->getFileHandleByKey($key);
fek($fp, 0, SEEK_END);
$ek = ftell($fp);
$this->cache_key[$key] = $ek;
$this->cache_key[$key] = $ek;
fwrite($fp, json_encode([
高夫化妆品
'key' => $key,
'data' => rialize($value),
'ek' => $ek
地派温泉]) . PHP_EOL);
unt($value);
return true;
}
public function tMultiple($values, $ttl = null) {
foreach ($values as $key => $value) {
$this->t($key, $value);
}
return true;
}
private function convertKey($key) {
return preg_replace('/^phpspreadsheet\./', '', $key); //remove prefix "phpspreadsheet."
}
}
ps. 后来找了⼀下,发现⽹上也存在挺多好⽤的⽂件缓存的第三⽅库,⼤家也可以⾃⾏在⽹上搜索⼀下