ch03 6章中 3章目

ch03 — ファイルに書く

スライドで見る

この章を AI と学ぶ

💬 AI に聞く質問例 3 件
  1. 「ch03 — ファイルに書く」のつまずきやすいポイントを、初学者向けに3つ教えてください

    ChatGPT Claude Gemini

  2. 「ch03 — ファイルに書く」について、自分の手で試せる練習問題を3つ出してください (難易度を上げながら)

    ChatGPT Claude Gemini

  3. 「ch03 — ファイルに書く」を学んだ後、次に学ぶと良いトピックは何ですか?理由も教えてください

    ChatGPT Claude Gemini

概要

書き込みも読み込みと対称で、手軽さの file_put_contents($path, $data) と、制御性の fopen('w') + fwrite + fclose の 2 系統。前者は「文字列を渡すだけで全部書く」、後者は「ハンドルを開きながら何度も書き足す」。普段使いはほぼ file_put_contents で済む。

モードの違い が地味に重要。デフォルトは 上書きモード (既存ファイルの中身を消してから書く)。file_put_contents(..., FILE_APPEND)fopen($path, 'a')追記モード になり、末尾に足す動きに変わる。ログや日次レポートなど「過去分を残しつつ書き足す」用途では追記必須。複数プロセスから同時に書く可能性がある場合は LOCK_EX (排他ロック) を併用する。

教育用ドリルでは 書き込み先を必ず sys_get_temp_dir() 配下 にして、終わったら unlink($tmp) で消す約束。「リポジトリ内のファイルを書き換えない」「CI で何度回しても残骸が残らない」ためのお作法。実務でも tempnam(sys_get_temp_dir(), 'prefix_') で一時ファイルを取って作業し、完了後に消すパターンは頻出。

学習目標

  • file_put_contents()文字列をファイルに書ける
  • fopen('w') + fwrite + fclose のパターンで書ける
  • 追記モード (FILE_APPEND / fopen('a')) と上書きモードの違いを言える
  • 書き込み先は必ず sys_get_temp_dir() 配下 にして、後で unlink で消す

ドリル

# 内容
01-write-and-read/ 一時ファイルに書いて読み返す (ラウンドトリップ)
02-append/ FILE_APPEND で 2 回書いて、追記されていることを読み返しで確認

確認のコツ

  • 書き込み先は tempnam(sys_get_temp_dir(), 'dojo_') で OS の一時領域に作る
  • 最後に unlink($tmp) でクリーンアップ (CI が同じ drill を何度回しても汚れない)
  • リポジトリ内のファイル (tests/data/...) には 書き込まない

解説スライド 全 8 枚

右の ボタン キー(またはスワイプ)で次のスライドに進めます。 下の「縦表示」を開くと全スライドを一気に読めます。

  1. ファイルに書く

    Lesson 14 / Chapter 3

  2. 書き込みも 2 系統

    関数 どんな時
    file_put_contents($path, $str) 文字列を 1 発で書く / 追記する
    fopen + fwrite + fclose 段階的に書きたい / 大きいデータを流す
    <?php
    // パターン A: 一発で書く
    $tmp = tempnam(sys_get_temp_dir(), 'dojo_');
    file_put_contents($tmp, "Hello, File!\n");
    
    // パターン B: fopen → fwrite → fclose
    $fp = fopen($tmp, 'w');     // 'w' = 上書きモード
    fwrite($fp, "line1\n");
    fwrite($fp, "line2\n");
    fclose($fp);
    
    unlink($tmp);   // クリーンアップ

    file-io トピックでは 大半が A で十分。B は慣れのため一度書く。

  3. 書き込み先は OS の一時ディレクトリへ

    // ✅ OK: 一時ディレクトリ
    $tmp = tempnam(sys_get_temp_dir(), 'dojo_');
    file_put_contents($tmp, "hi\n");
    unlink($tmp);
    
    // ❌ NG: drill 内に書く (リポジトリが汚れる)
    file_put_contents(__DIR__ . '/output.txt', "hi\n");
    • sys_get_temp_dir() = OS の一時領域 (Mac/Linux なら /tmp)
    • tempnam($dir, $prefix) = その中に 被らないファイル名 を作って返す (ゼロバイトの空ファイル付き)
    • unlink($path) = ファイルを消す

    → 「採点が何度走っても、リポジトリの状態が変わらない」 のがゴール。

  4. file_put_contents の典型形

    <?php
    $tmp = tempnam(sys_get_temp_dir(), 'dojo_');
    
    // 上書き (デフォルト)
    $bytes = file_put_contents($tmp, "Hello, File!\n");
    echo "wrote {$bytes} bytes\n";   // wrote 13 bytes
    
    // 読み返して確認
    echo file_get_contents($tmp);    // Hello, File!
    
    unlink($tmp);
    • 戻り値は 書いたバイト数 (失敗時 false)
    • ファイルが既にあれば デフォルトで上書き
    • 第 3 引数で挙動を変えられる (FILE_APPEND / LOCK_EX など)
  5. 追記モード — FILE_APPEND

    <?php
    $tmp = tempnam(sys_get_temp_dir(), 'dojo_');
    
    file_put_contents($tmp, "line1\n");                  // 中身: "line1\n"
    file_put_contents($tmp, "line2\n", FILE_APPEND);     // 中身: "line1\nline2\n"
    file_put_contents($tmp, "line3\n", FILE_APPEND);     // 中身: "line1\nline2\nline3\n"
    
    echo file_get_contents($tmp);
    // line1
    // line2
    // line3
    
    unlink($tmp);
    • FILE_APPEND を渡すと 末尾に追記 (元の中身を保つ)
    • 渡さないと 上書き (前の中身は消える)

    → ログ書き込みは FILE_APPEND | LOCK_EX のセットが定番。

  6. fopen のモード一覧 (主要なもの)

    モード 意味 既存ファイル
    'r' 読み込み そのまま
    'w' 書き込み (上書き) 中身が消える (truncate)
    'a' 追記 末尾に追記
    'r+' 読み書き そのまま
    'w+' 読み書き (上書き) 中身が消える
    'a+' 読み書き (追記) 末尾に追記
    $fp = fopen($tmp, 'a');     // 追記モード
    fwrite($fp, "extra line\n");
    fclose($fp);

    w は中身を消す」 が一番の落とし穴。設定ファイルを 'w' で開いて空にしてしまう事故が定番。

  7. 書いたら必ず読み返して検算

    <?php
    $tmp = tempnam(sys_get_temp_dir(), 'dojo_');
    
    // 書く
    file_put_contents($tmp, "Hello, File!\n");
    
    // 読む (= 書いた内容を検算)
    echo file_get_contents($tmp);
    
    // 後始末
    unlink($tmp);
    • 採点では 「書いたものを読み返した結果」expected.txt と比べる
    • 「書いた」と「保存できた」は 別物fclose / file_put_contents の戻り値で確認する癖を

    → ドリル 01 はこの 「書く → 読む → 消す」のラウンドトリップ を体験する形。

  8. このチャプターでできるようになること

    file_put_contents でファイルに 1 発で書ける ✅ fopen('w') + fwrite + fclose で書ける ✅ FILE_APPEND / fopen('a') で追記できる ✅ 'w' モードは 既存の中身を消す ことを認識している ✅ 書き込み先は sys_get_temp_dir() 配下にして unlink で消す癖がついた

    → ドリルへ

1 / 8
📜 スライドを全部一気に読む(縦表示)

Lesson 14 / Chapter 3


書き込みも 2 系統

関数 どんな時
file_put_contents($path, $str) 文字列を 1 発で書く / 追記する
fopen + fwrite + fclose 段階的に書きたい / 大きいデータを流す
<?php
// パターン A: 一発で書く
$tmp = tempnam(sys_get_temp_dir(), 'dojo_');
file_put_contents($tmp, "Hello, File!\n");

// パターン B: fopen → fwrite → fclose
$fp = fopen($tmp, 'w');     // 'w' = 上書きモード
fwrite($fp, "line1\n");
fwrite($fp, "line2\n");
fclose($fp);

unlink($tmp);   // クリーンアップ

file-io トピックでは 大半が A で十分。B は慣れのため一度書く。


書き込み先は OS の一時ディレクトリへ

// ✅ OK: 一時ディレクトリ
$tmp = tempnam(sys_get_temp_dir(), 'dojo_');
file_put_contents($tmp, "hi\n");
unlink($tmp);

// ❌ NG: drill 内に書く (リポジトリが汚れる)
file_put_contents(__DIR__ . '/output.txt', "hi\n");
  • sys_get_temp_dir() = OS の一時領域 (Mac/Linux なら /tmp)
  • tempnam($dir, $prefix) = その中に 被らないファイル名 を作って返す (ゼロバイトの空ファイル付き)
  • unlink($path) = ファイルを消す

→ 「採点が何度走っても、リポジトリの状態が変わらない」 のがゴール。


file_put_contents の典型形

<?php
$tmp = tempnam(sys_get_temp_dir(), 'dojo_');

// 上書き (デフォルト)
$bytes = file_put_contents($tmp, "Hello, File!\n");
echo "wrote {$bytes} bytes\n";   // wrote 13 bytes

// 読み返して確認
echo file_get_contents($tmp);    // Hello, File!

unlink($tmp);
  • 戻り値は 書いたバイト数 (失敗時 false)
  • ファイルが既にあれば デフォルトで上書き
  • 第 3 引数で挙動を変えられる (FILE_APPEND / LOCK_EX など)

追記モード — FILE_APPEND

<?php
$tmp = tempnam(sys_get_temp_dir(), 'dojo_');

file_put_contents($tmp, "line1\n");                  // 中身: "line1\n"
file_put_contents($tmp, "line2\n", FILE_APPEND);     // 中身: "line1\nline2\n"
file_put_contents($tmp, "line3\n", FILE_APPEND);     // 中身: "line1\nline2\nline3\n"

echo file_get_contents($tmp);
// line1
// line2
// line3

unlink($tmp);
  • FILE_APPEND を渡すと 末尾に追記 (元の中身を保つ)
  • 渡さないと 上書き (前の中身は消える)

→ ログ書き込みは FILE_APPEND | LOCK_EX のセットが定番。


fopen のモード一覧 (主要なもの)

モード 意味 既存ファイル
'r' 読み込み そのまま
'w' 書き込み (上書き) 中身が消える (truncate)
'a' 追記 末尾に追記
'r+' 読み書き そのまま
'w+' 読み書き (上書き) 中身が消える
'a+' 読み書き (追記) 末尾に追記
$fp = fopen($tmp, 'a');     // 追記モード
fwrite($fp, "extra line\n");
fclose($fp);

w は中身を消す」 が一番の落とし穴。設定ファイルを 'w' で開いて空にしてしまう事故が定番。


書いたら必ず読み返して検算

<?php
$tmp = tempnam(sys_get_temp_dir(), 'dojo_');

// 書く
file_put_contents($tmp, "Hello, File!\n");

// 読む (= 書いた内容を検算)
echo file_get_contents($tmp);

// 後始末
unlink($tmp);
  • 採点では 「書いたものを読み返した結果」expected.txt と比べる
  • 「書いた」と「保存できた」は 別物fclose / file_put_contents の戻り値で確認する癖を

→ ドリル 01 はこの 「書く → 読む → 消す」のラウンドトリップ を体験する形。


このチャプターでできるようになること

file_put_contents でファイルに 1 発で書ける ✅ fopen('w') + fwrite + fclose で書ける ✅ FILE_APPEND / fopen('a') で追記できる ✅ 'w' モードは 既存の中身を消す ことを認識している ✅ 書き込み先は sys_get_temp_dir() 配下にして unlink で消す癖がついた

→ ドリルへ

この章で取り組む 演習問題の流れ (2ステップ)
  1. 01 ドリル 01 — 一時ファイルに書いて読み返す README.md starter.php answer.php
  2. 02 ドリル 02 — `FILE_APPEND` で追記する README.md starter.php answer.php

演習問題の詳細

この章の演習問題の内容を読めます。実際に手元で解くには教材リポジトリを clone してください。

ドリル 01 — 一時ファイルに書いて読み返す

問題

OS の一時ディレクトリに一時ファイルを作って "Hello, File!\n" を書き込み、その中身を読み返して標準出力に出してください。最後にその一時ファイルを unlink で消してください。

期待される出力:

Hello, File!

ヒント

$tmp = tempnam(sys_get_temp_dir(), 'dojo_io_');
file_put_contents($tmp, "Hello, File!\n");
echo file_get_contents($tmp);
unlink($tmp);
  • tempnam($dir, $prefix) : $dir 配下に被らないファイル名を作り、空ファイルを置いてパスを返す
  • sys_get_temp_dir() : OS の一時ディレクトリパス (Mac/Linux なら /tmp)
  • unlink($path) : ファイルを削除する

なぜ一時ディレクトリに書くのか

  • リポジトリ内 (__DIR__ 配下) に書くと、採点を回すたびにリポジトリが汚れる
  • sys_get_temp_dir() 配下 + unlink で消す = 「実行後は何も残らない」 が file-io トピックの作法

つまづいたら

  • Hello, File! の後に空行が 1 つ余計に出る → echo file_get_contents($tmp) . "\n"; のように追加で改行を足していないか
  • unlinkWarning が出る → tempnam の戻り値 (フルパス) を渡しているか。null や空文字を渡していないか

🧪 ブラウザで試す

スライドのコードを写経して ▶ 実行、自分で書いて 📝 採点 で答え合わせ。初回のみ PHP ランタイム読込で数秒かかります。

PHP ランタイム未読込

          

        

ドリル 02 — `FILE_APPEND` で追記する

問題

一時ファイルに以下の順で書き込み、最終的な中身を読み返して出力してください。最後に unlink で削除します。

  1. "line1\n" を書く (上書き)
  2. "line2\n"FILE_APPEND で追記
  3. "line3\n"FILE_APPEND で追記
  4. ファイル全体を読み返して echo
  5. unlink で消す

期待される出力:

line1
line2
line3

ヒント

$tmp = tempnam(sys_get_temp_dir(), 'dojo_io_');
file_put_contents($tmp, "line1\n");
file_put_contents($tmp, "line2\n", FILE_APPEND);
file_put_contents($tmp, "line3\n", FILE_APPEND);
echo file_get_contents($tmp);
unlink($tmp);
  • FILE_APPEND を渡さないと 上書き されて前の中身が消える
  • ログ書き込みでは FILE_APPEND | LOCK_EX (排他ロック付き追記) が定番

つまづいたら

  • 出力が line3 だけになる → 2 回目以降の file_put_contentsFILE_APPEND を渡し忘れている (= 上書き)
  • line1line2line3 のように改行が無い → 各文字列の末尾 "\n" を書き忘れている ("line1" ではなく "line1\n")

🧪 ブラウザで試す

スライドのコードを写経して ▶ 実行、自分で書いて 📝 採点 で答え合わせ。初回のみ PHP ランタイム読込で数秒かかります。

PHP ランタイム未読込

          

        

演習問題(2問)

  1. ドリル 01 — 一時ファイルに書いて読み返す

    README.md starter.php answer.php

  2. ドリル 02 — `FILE_APPEND` で追記する

    README.md starter.php answer.php

サイト内で問題文・雛形・解答例を確認できます。実際に手元で解くには教材リポジトリを clone してください。

完了にすると進捗に反映されます