PHP - BASIC - 11. PHPのファイルシステムを扱う関数 - 8. 読み込み(書き込み)に失敗する場合

ファイルシステム関数は、文字列を扱う関数や配列を扱う関数と異なり、プログラムの実行環境の影響を受けます。たとえば冒頭で取り上げたプログラム( fs1.php )をもう一度見てみましょう。

<?php
$str = "Hello World" . PHP_EOL;
$file = "hello.txt";
file_put_contents($file, $str);

このプログラムは一見すると正しく動作するように見えますが、以下のようなケースでは実行時にエラーとなってしまいます。

  • 他のプログラムが hello.txt ファイルを処理(ロック)している場合
  • ファイルの書き込み権限がない場合
  • ディスク容量が不足している場合

上記のようなケースはプログラムに不具合があるのではなく、プログラムの動作する環境側の問題と言えます。このような問題はファイルシステムのやりとり以外にも、ネットワークやデータベースにアクセスする場合にも考えないといけません。

そのためこれまでに学習してきたファイルシステムを扱う関数のほとんどは、実行時にエラーが発生した場合、関数の戻り値に false を返す仕組みになっています。

たとえば先ほどのプログラム( fs1.php )の場合、以下のように file_put_contents 関数の戻り値を判定することでファイルの書き込未失敗を検出できます。

<?php
$str = "Hello World" . PHP_EOL; 
$file = "hello.txt"; 
$result = file_put_contents($file, $str); 
if ($resutl === false) {
  echo "error" . PHP_EOL; 
}

file_put_contents 関数は、正常にファイルに書き込めた場合は、書き込んだデータのバイト数を戻り値で返しますが、ファイルの書き込みに失敗した場合は false を返却するようになっています。上記のように戻り値を if 文で判定することで、ファイル書き込みに失敗した場合の後処理を実装できます。

もう一つ例を見ておきましょう。以前に取り上げたファイルを読み込むプログラム( fs5.php )を見てみましょう。

<?php
$file = "hello.txt"; 
$handle = fopen($file, "r"); 
while(($line = fgets($handle)) !== false) {
  echo $line; 
}
fclose($handle); 

fopen 関数で読み込み対象のファイル名 hello.txt を指定していますが、実行環境によっては hello.txt ファイルが存在しない可能性もありえます。 fopen 関数は、正常にファイルを開けた場合は戻り値としてファイルポインタを返しますが、読み込み対象のファイルが存在しない場合やアクセス権限が不足する場合などは戻り値に false を返します。そのため以下のように実装することでファイル読み込みの失敗を検出できます。

<?php
$file = "hello.txt"; 
$handle = fopen($file, "r"); 
if ($handle === false) {
  die("can't open file"); 
}
while(($line = fgets($handle)) !== false) {
  echo $line; 
}
fclose($handle); 

上記のプログラムでは $handle 変数が false の場合には die 関数を使って処理を異常終了させています。PHPのプログラムは die 関数を呼び出すとその場でメッセージを出力して処理を終えるようになっています。ここではファイルのオープンに失敗した場合は後続の処理を実行せずに停止するようにしています。

ここではカレントディレクトリからhello.txtファイルを削除して、プログラムを実行してみましょう。

$ php fs5.php
PHP Warning:  fopen(hello.txt): failed to open stream: No such file or directory in /Users/your_name/Desktop/code-php/fs5.php on line 3
can't open file

実行結果を見ると、 die 関数による can't open file メッセージだけでなく、Warningメッセージも出力されています。実行時にWarningメッセージを非表示にするには fopen 関数の呼び出し部分にエラー制御演算子 @ を使います。

<?php
$file = "hello.txt"; 
$handle = @fopen($file, "r"); 
if ($handle === false) {
  die("can't open file"); 
}
while(($line = fgets($handle)) !== false) {
  echo $line; 
}
fclose($handle); 

もう一度プログラムを実行してみましょう。

$ php fs5.php
can't open file

実行結果からWarningメッセージが抑制されているのがわかります。

まとめ

  • ファイルシステム関数は、プログラムの実行環境の影響を受ける
    • 他のプログラムが対象ファイルを処理(ロック)している場合
    • ファイルへのアクセス権限がない場合
    • ファイル書き込み時にディスク容量が足りない場合 など
  • ファイルシステムを扱う関数のほとんどは、実行時にエラーが発生した場合、戻り値にfalseを返す
  • 関数呼び出し時に、エラー制御演算子 @ を付けると警告メッセージを抑制できる