PHP
PHPDay 11

PHPファイル操作機能一覧

PHPマニュアルファイルシステム関数には、さまざまな函数が雑多に並んでますが、この記事では機能を分類しながら、PHPのファイル操作方法について具体的に説明していきます。

機能の種類

PHPでファイルを操作するための機能には、大きく分けて3種類あります。

  • ファイル名型 - ファイル名を引数として取る函数
  • ストリーム型 - ストリーム(ファイルポインタ)を引数としてとる函数
  • オブジェクト型 - SplFileObject(SplFileInfo)のメソッド

この3種類の機能にはそれぞれ特徴があります。どれか一つの型だけに統一することはできないのですが、向く場面向かない場面があるので表に整理します。

さらにてっとり早く知りたい人はPHPでファイルを開いて読み込むを読んでね。

早見表

機能 \ 引数 ファイル名型 ストリーム型 オブジェクト型
ファイルを操作する準備 不要 fopen() new SplFileObject()
内容の全体を文字列として取得 file_get_contents() stream_get_contents() SplFileObject::fread() + SplFileInfo::getSize()
内容の一部を文字列として取得 file_get_contents() fread() SplFileObject::fread()
文字列をファイルに書き込み file_put_contents() fwrite() SplFileObject::fwrite()
内容を行区切りで取得 file() stream_get_line() / fgets() SplFileObject::fgets()
内容をバッファに出力 readfile() fpassthru() SplFileObject::fpassthru()
ファイルロック file_put_contents()LOCK_EX flock() SplFileObject::flock()
一時ファイル生成 tempnam() (ファイル名生成のみ) fopen('php://temp', 'rw') または tmpfile() new SplTempFileObject()
ファイルコピー copy() 読み込みと書き込みの複合で実現 読み込みと書き込みの複合で実現

おまけ: 「ファイル名」とは

PHPで「ファイル名」として利用できるのは、以下のような文字列です。

ローカルファイルシステムのフルパス

あまり説明することもないですが、普通のファイル名のパスです。UNIX系OSでは/から始まり、WindowsではC:\のようなドライブレターから始まる文字列です。

include_path内のファイル名

あまりおすすめしないです。

include_pathphp.iniファイルまたはini_set()関数(またはset_include_path())でセットできる設定です。

<?php
var_dump(get_include_path());
//=> string(44) ".:/usr/local/Cellar/php/7.3.0/share/php/pear"

しれっと.が入ってるので、ディレクトリを指定しなくてもファイルを開けるように見えるのは、そのせいです。

プロトコル/ラッパー

PHPマニュアルに掲載されてるのは以下の通りです。

  • php:// — さまざまな入出力ストリームへのアクセス
  • file:// — ローカルファイルシステムへのアクセス
  • http:// — HTTP(s) URL へのアクセス
  • ftp:// — FTP(s) URL へのアクセス
  • zlib:// — 圧縮ストリーム
  • data:// — データ (RFC 2397)
  • glob:// — パターンにマッチするパス名の検索
  • phar:// — PHP アーカイブ
  • ssh2:// — Secure Shell 2
  • rar:// — RAR
  • ogg:// — オーディオストリーム
  • expect:// — 対話的プロセスストリーム

これらは普通のファイルシステムと同じように操作することができます。

ただし全ての操作が実装されてるわけではなく、読み込みしかできないプロトコルも多いです。

// file_get_contents("http://httpbin.org/get") と同じこと
$f = fopen("http://httpbin.org/get", "r");
var_dump(stream_get_contents($f));
// string(158) "{
//   "args": {},
//   "headers": {
//     "Connection": "close",
//     "Host": "httpbin.org"
//   },
//   "origin": "111.97.185.93",
//   "url": "http://httpbin.org/get"
// }
// "

このプロトコルはユーザーが拡張できます。PHPテストに利用できる仮想ファイルシステムであるvfsStreamは、この仕組みの上に構築されてます。

結局どれがいいの?

表に挙げたように、実際どれもほとんど同じことができます。ただ、関数をまたいでファイルのようなものを扱うときに、どれを使うかはある程度は一貫性を持たせた方がよいでしょう。

  • ファイル名型
    • 初期化の必要がないので操作が簡単
    • ファイル名は型としては単なる文字列なので型として区別して扱いにくい
  • ストリーム型 (resource)
    • STDIN, STDOUT, STDERR など定義済みの定数がある
      • これらの入出力を差し替えるものとしてテストに利用可能
    • proc_open()と相互運用できる
    • 型名としてはresourceだが、これは型宣言に記述できない
  • オブジェクト型
    • SplFileObjectや(SplFileInfo)などがある
    • すべての操作がオブジェクトのメソッドとして実装されてるのでわかりやすい (=メソッド名の補完ができる)
    • ストリーム型の機能と相互運用できない

アプリケーションの設計に属する問題なので好きなものを選んでください。