【PHP】CSV形式の大量のダミーデータをFakerで作成する

# はじめに
CSV形式でダミーデータを大量に作りたい時ってありますよね。
数字の採番であれば、エクセルでさくっと作れますが、氏名とか郵便番号とかのダミーデータに作りたい場合って、結構大変ですよね。。

今日は、LaravelのFactoryで使われているFakerというライブラリを使って、さくっとダミーデータを作成しましょう！ってお話です。


# 使用技術
PHP >= 5.3.3
composer 
[faker](https://github.com/fzaninotto/Faker)

# ソースコード
https://github.com/westhouseK/csv-generator

# 試したい人向け
```
git clone https://github.com/westhouseK/csv-generator.git
cd csv-generator
composer install
php index.php
```

# 実装
### メインルーチン

```php:index.php
$csv = new Csv(new SplFileObject('test.csv', 'w'));
// 任意でヘッダーをセット
$header = ['name', 'tel', 'mail', 'birthday']; 
// 生成したいレコード数
$records = 10;

// ヘッダーを先に書き込む
$csv->set_header($header)->create_header();
// ダミーデータを作成🐹
$csv->set_records($records)->create_test_data(new MyFaker());
```

`Csv`インタスンスに`SplFileObject`をインジェクションしています。PHPでCSVを扱うなら[SplFileObject](https://www.php.net/manual/ja/class.splfileobject.php)が手軽でおすすめです！
出力したいCSVのヘッダーを任意で生成することが可能です。


### Csvクラス

```php:Csv.php

class Csv {

    // ファイル操作のインスタンス
    private object $file_object;

    // csvのヘッダー
    private array $header = [];

    // 生成したいレコード数
    private int $records = 0;

    public function __construct(object $file_object) {
        $this->file_object = $file_object;
    }

    // ヘッダーをセットする
    public function set_header(array $header): object {
        $this->header = $header;
        return $this;
    }

    // レコード数をセットする
    public function set_records(int $records): object {
        $this->records = $records;
        return $this;
    }

    // ヘッダーを保存する
    public function create_header(): void {
        $this->file_object->fputcsv($this->header);
    }

    // コンテンツを保存する
    public function create_test_data(object $creater) {

        for($i = 0; $i < $this->records; $i++) {
            $contents = [];
            $contents[] = $creater->create_name(); // (1)
            $contents[] = $creater->create_phone_number();
            $contents[] = $creater->create_email();
            $contents[] = $creater->create_date();

            $this->file_object->fputcsv($contents);
        }
    }
}
```
`$creater`はFakerのインスタンスです。`(1)`で直接fakerを呼び出していないのは、CSVクラスにfakerを依存させたくなかったからです。他のダミーデータ作成ライブラリを使いたくなった時に、インジェクションした方が汎用的なクラスとなるわけです。


```php:Myfaker.php
/**
 * fakerをラップするクラス
 */
class MyFaker {

    // fakerのインスタンス
    private object $faker;

    public function __construct() {
        $this->faker = Faker\Factory::create();
    }

    // 名前を生成する
    public function create_name(): string {
        return $this->faker->name;
    }

    // 電話番号を生成する
    public function create_phone_number() {
        return $this->faker->phoneNumber;
    }

    // メールを生成する
    public function create_email() {
        return $this->faker->email;
    }

    // 日付を生成する
    public function create_date() {
        return $this->faker->date($format='Y-m-d',$max='now');
    }
}
```
上記に、Fakerの関数をラップするようにしてあげると、自分の好きなように追加することが可能です。

# 出力結果
以下のような、test.csvが出力されます。

```csv:test.csv
name,tel,mail,birthday
"Dr. Mariano Dickinson II",1-171-037-2947,wolf.maureen@gmail.com,1993-10-31
"Carissa Lang",(443)151-6762,jkeeling@hotmail.com,1979-01-10
"Jarrod Blick Jr.",793-175-2742x626,viva49@hotmail.com,2020-07-16
･･･
```

# 出力速度

#### 条件

- 4列出力 
- MacBook Air 2019(10.14.6), プロセッサ 1.6 GHz Intel Core i5, メモリ 8GBで実行
- php memory_limit 128M(default)

|レコード数|実行時間(秒)|
|:-----------|------------:|
|10|0.04|
|100|0.1|
|1000|0.7|
|10000|7〜10|
|100000|87〜95|
|1000000|1007|

100万レコード作るのはそれなりに時間がかかるので、やらないことをおすすめします。

# 終わりに
オブジェクト指向を少し意識して作ってみました✌
呼び出し元がスッキリしたコードが書けるように心がけていきたいです。

[SplFileObjectは遅い](https://notepad-blog.com/content/61/)らしいので、`fopen()`で実装した方がよかったかなと思ったり...

# 参考
[PHPでダミーデータを作る](https://qiita.com/zaburo/items/4487b23543ce88ce7f0c)
[[Laravel5.1]Fakerチートシート](https://qiita.com/tosite0345/items/1d47961947a6770053af)