PHPでExcel出力する際にfromArrayが便利ですが、0が空でセルに表示される問題の対応

この記事は [BRIGHT VIE Advent Calendar 2017 - Qiita](https://qiita.com/advent-calendar/2017/brightvie) 19日目の記事になります。

とある案件で、PHPでExcel出力をする必要があり、
そのときに0を表示したいのに空でセルに表示されている問題があったのでその対応メモです。

# はじめに

PHPでExcel出力するのは、PHPExcel_IOFactoryを利用するととっても簡単！（調べればすぐですね！）

## 実装

```php
//ライブラリの読込
require_once 'PHPExcel.php';
require_once 'PHPExcel/IOFactory.php';

// テンプレートファイル読み込み
$reader = PHPExcel_IOFactory::createReader('Excel2007');
$excel = $reader->load("template.xlsx"));

// シートの設定を行う
$excel->setActiveSheetIndex(0);
$sheet = $excel->getActiveSheet();

/******************
 * 書き込み処理 *
 ******************/
// セルを指定して書き込み
$sheet->setCellValue('B2' , "書き込みたいデータ");

// 配列データを書き込み(B6のセルから$arrayのデータを書き込む)
$sheet->fromArray($array, null, 'B6');


/******************
 * 出力処理 *
 ******************/
header('Content-Type: application/octet-stream');
//　ダウンロードするファイル名を設定
header('Content-Disposition: attachment;filename="download_test.xlsx"');

// EXCEL2007で出力
$writer = PHPExcel_IOFactory::createWriter($book, "Excel2007");
$writer->save('php://output');
```

はい、これだけで実施できちゃいます。
集計機能などExcelの出力状態がわかっていれば、
fromArrayで予め表示用の配列を作っておけば出力処理はすぐです！

# fromArrayで0を出力していたはずなのにセルの状態が空になる

ここで本題です。
こちらは集計画面の内容をExcelに出力するという機能で利用していたのですが、
0のデータが軒並み空文字になっていました。

なんでだろうと思ってさぐっていると、いつもお世話になっているstack overflowに下記のような記載が...

> I think you are a victim of loosely-typed comparisons here - you have specified null as your second parameter to fromArray(), which represents the Value in source array that stands for blank cell. Since null == 0 this means that zero will result in a blank cell unless you set the fourth argument to true.

引用元: [PHPExcel outputting zeros as blank cells -stack overflow](https://stackoverflow.com/questions/9704434/phpexcel-outputting-zeros-as-blank-cells)


fromArrayメソッドの第二引数は、セルが空になる定義で、今回の場合だと「null」を指定している。
そのため、fromArrayでセルに0を書き出すときには、「null == 0」な曖昧な判定で行われてしまっているため、
0が出力されずに空になってしまっているという原因ぽい。


実際にどんな処理なのかPHPExcelのfromArrayメソッドをGitHubで見てみました。


まずは、fromArrayメソッドの定義部分。
第二引数に「$nullValue」、第四引数に「$strictNullComparison」というのがあるのが分かる。

```php
/**
 * Fill worksheet from values in array
 * 
 * @param array $source Source array
 * @param mixed $nullValue Value in source array that stands for blank cell
 * @param string $startCell Insert array starting from this cell address as the top left coordinate
 * @param boolean $strictNullComparison Apply strict comparison when testing for null values in the array
 * @throws PHPExcel_Exception
 * @return PHPExcel_Worksheet
 */
 public function fromArray($source = null, $nullValue = null, $startCell = 'A1', $strictNullComparison = false) |
```
参照元: [PHPExcel Worksheet.php  2406行目付近 - GitHub](https://github.com/PHPOffice/PHPExcel/blob/1c8c2379ccf5ab9dd7cb46be965821d22173bcf4/Classes/PHPExcel/Worksheet.php#L2406)


そして肝心の判定処理

```php
if ($strictNullComparison) {
  if ($cellValue !== $nullValue) {
    // Set cell value
    $this->getCell($currentColumn . $startRow)->setValue($cellValue); 
  }
} else {
  if ($cellValue != $nullValue) {
    // Set cell value
    $this->getCell($currentColumn . $startRow)->setValue($cellValue); |
  }
}
```
参照元: [PHPExcel Worksheet.php 2430行目付近 - GitHub](https://github.com/PHPOffice/PHPExcel/blob/1c8c2379ccf5ab9dd7cb46be965821d22173bcf4/Classes/PHPExcel/Worksheet.php#L2430)

確かに、第四引数の「strictNullComparison」をtrueにしていると、
「cellValue !== nullValue」厳密なチェックが行われており、
そうでない場合には「cellValue != nullValue」と曖昧なチェックが行われている。

なろほど...

## 第四引数のstrictNullComparisonをtrueにする

ということで、

```php
// 配列データを書き込み(B6のセルから$arrayのデータを書き込む)
$sheet->fromArray($array, null, 'B6', true);
```

とすることで、Excelに0がきちんと出力されるようになりましたー


# まとめ

新卒の頃曖昧な型チェックを行うのであれば、起こり得る全ての判定パターンを理解した上で使っているのかを厳しくチェック頂いたためか、
今では迷うことはなくなりましたが...（チーム開発となるとバグを防ぐために基本的には厳密な型チェックを利用）

曖昧チェックの良さはありつつも、こういうハマリポイント？もあるのでなんだかなぁという気持ちにはなりました。