式の評価処理
PhpSpreadsheetはメモリ上のスプレッドシートを操作するため、式の計算機能を内蔵しています。セルには数値や文字列を格納する「値セル」と、評価可能な数式を含む「式セル」があります。例として=SUM(B2:B11)はB2からB11の合計値を算出します。
式の評価はcalculateCellValue()メソッドで実行可能です:
$book = new Spreadsheet();
$sheet = $book->getActiveSheet();
$result = $sheet->calculateCellValue('F12');
このメソッドは式を評価し、結果を数値または文字列で返します。Invoiceデモで上記コードを実行すると72が得られます。
特筆すべき点は、行・列の挿入時に式が自動調整される点です。例えばF12セルにSUM(F3:F10)が設定されている場合、
$sheet->insertNewRowBefore(5, 3);
を実行すると、式は自動的にSUM(F3:F13)へと更新されます。挿入されたセルの書式設定も元のセルを継承するため、Excelと同様の動作を実現しています。
計算キャッシュの管理
式の評価結果はキャッシュに保存されるため、同一セルの再評価時は計算をスキップします。この仕組みにより、計算負荷の高い式でもパフォーマンスを維持できます。
ただし、基となるデータが変更された場合はキャッシュを無効化する必要があります:
// キャッシュを完全無効化
Calculation::getInstance($book)->setCacheEnabled(false);
// キャッシュをクリア(有効状態を維持)
Calculation::getInstance($book)->clearCacheData();
デフォルトではキャッシュが有効ですが、頻繁にデータを更新するシナリオではsetCacheEnabled(false)を事前に設定することを推奨します。
日付・時刻の取り扱い
日付関数の出力形式はFunctions::setReturnDateType()で制御可能です:
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
// Excel互換形式に設定
Functions::setReturnDateType(Functions::RETURN_DATE_EXCEL);
// PHP DateTimeオブジェクト形式
Functions::setReturnDateType(Functions::RETURN_DATE_OBJECT);
| 定数 | データ形式 | 有効範囲 |
|---|---|---|
| RETURN_DATE_NUMERIC | PHPタイムスタンプ(整数) | 1901-2038年 |
| RETURN_DATE_OBJECT | DateTimeオブジェクト | 全期間対応 |
| RETURN_DATE_EXCEL | Excelシリアル値(浮動小数) | 1900-9999年 |
カレンダーベースの設定はDate::setExcelCalendar()で変更可能です:
use PhpOffice\PhpSpreadsheet\Shared\Date;
// Mac用1904基準カレンダに切り替え
Date::setExcelCalendar(Date::CALENDAR_MAC_1904);
日付関数のサンプル
DATE関数の利用例:
// 2023年12月25日をExcelシリアル値で取得
Functions::setReturnDateType(Functions::RETURN_DATE_EXCEL);
$excelDate = Functions::DATE(2023, 12, 25); // 45285.0
// 同日をDateTimeオブジェクトで取得
Functions::setReturnDateType(Functions::RETURN_DATE_OBJECT);
$dateTime = Functions::DATE(2023, 12, 25); // DateTimeインスタンス
DATEDIF関数は日付間の差分を計算します:
$start = '2020-01-01';
$end = '2023-03-15';
// 3年2ヶ月14日を日数換算
$days = Functions::DATEDIF($start, $end, 'd'); // 1169
// 月単位の差分
$months = Functions::DATEDIF($start, $end, 'm'); // 38
データベース関数の実装例
DAVERAGE関数は条件に合致するデータの平均値を算出します。実装例:
// 商品データセット
$productData = [
['商品', '高さ', '年齢', '収量', '利益'],
['りんご', 15, 18, 12, 90.50],
['みかん', 10, 10, 8, 85.00],
['さくらんぼ', 12, 13, 7, 95.00],
['りんご', 13, 14, 9, 70.00]
];
// 条件設定
$criteria = [
['商品', '高さ'],
['りんご', '>12']
];
// ワークシートに反映
$sheet->fromArray($criteria, null, 'A1');
$sheet->fromArray($productData, null, 'A4');
// 平均収量を計算
$sheet->setCellValue('A10', '=DAVERAGE(A4:E7, "収量", A1:B2)');
$avgYield = $sheet->getCell('A10')->getCalculatedValue(); // 10.5
DCOUNT関数は数値を含むセルのカウントに使用します:
$sheet->setCellValue('A11', '=DCOUNT(A4:E7, "高さ", A1:A2)');
$count = $sheet->getCell('A11')->getCalculatedValue(); // 2
DMAX/DMINは最大値・最小値を取得します:
$sheet->setCellValue('A12', '=DMAX(A4:E7, "利益", A1:B2)');
$maxProfit = $sheet->getCell('A12')->getCalculatedValue(); // 90.50
制限事項と対処法
計算エンジンには以下の制限があります:
- Excelの
&演算子の優先順位がPHPと異なる - 数値と文字列の演算でエラーが発生しない場合がある
- Xlsフォーマットでは一部関数がサポートされない
特に日付計算では、タイムゾーン設定が重要です:
// タイムゾーンを東京標準時に設定
Date::setDefaultTimezone('Asia/Tokyo');
// Excelシリアル値をDateTimeに変換
$dateTime = Date::excelToDateTimeObject(45285.0); // 2023-12-25