第1回 File クラス - ファイル操作のテクニック - PEAR講座

PHP基礎編

くまっち先生のPEAR講座

Lecutures on PHP

第1回 File クラス - ファイル操作のテクニック (その2)

 このエントリーをはてなブックマークに追加

ファイルポインタ情報はどうやって作っている?

続いて、前節で登場した _getFilePointer の中身を見てみることにしましょう。くまっち先生

先頭に「_」(アンダースコア)をつけた名称をもつものは、クラス内のプライベートメソッド(クラス内部からの使用に限定)という意味を持っています。(*2) 主に処理内容を共通して使いたい場合に作成し利用します。実際今回の File クラス内に存在するいくつかのメソッドでこのプライベートメソッドを使用し処理の共通化を行っています。

またより高度な例としては「処理内容を抽象化したい」という意図もあります。抽象化などというとちょっと難しく感じるかもしれませんが、今回の場合ですと「ファイルポインタを取得する」という機能を1つのメソッドで実現しているということがそれにあたります。

ではこの機能はどのように実現しているのでしょうか。リスト4はそのコードの抜粋です。read メソッドのみ関連する箇所を抜き出してみました。

リスト4 _getFilePointer メソッドの内容 (一部抜粋)

function &
_getFilePointer($filename$mode$lock false)
{
  
$filePointers = &PEAR::getStaticProperty('File''filePointers');
        
  
// Win32 is case-insensitive
  
if (OS_WINDOWS) {
    
$filename strToLower($filename);
  }     
  
  
// check if file pointer already exists
  
if (!isset($filePointers[$filename][$mode]) || 
    !
is_resource($filePointers[$filename][$mode])) {
            
    
// check if we can open the file in the desired mode
    
switch ($mode)
    {
      case 
FILE_MODE_READ:
        if (!
preg_match('/^.+(?<!file):\/\//i'$filename) &&
            !
file_exists($filename)) {
          return 
PEAR::raiseError("File does not exist: $filename");
        }
        break;
                
        
/////////////////
        // 中略
        /////////////////
    
}
            
    
// open file
    
$filePointers[$filename][$mode] = @fopen($filename$mode);
    if (!
is_resource($filePointers[$filename][$mode])) {
      return 
PEAR::raiseError('Failed to open file: ' $filename);
    }
  }
        
  
/////////////////
  // 中略
  /////////////////

  
return $filePointers[$filename][$mode];
}

read と比べるとなにやら複雑なことをしているようにも見えますが、このコードはあくまで「ファイルポインタを取得する」ことを目標としたコードです。落ち着いて見ていきましょう。

まずはじめに目につく箇所は、$filePointers 変数に PEAR::getStaticProperty (*3) という処理を行っていることです。そして静的変数として参照できる $filePointers を確認し、先ほどの read メソッドの (2) に近いことを行っています。くまっち先生

これはどういうことでしょう?read メソッド内で静的変数として値を保持するようにしているにも関わらず、そのメソッド内で呼び出される _getFilePointer 内でも同じような情報の保持をしていることになります。

一方、静的変数としてファイルポインタ情報を保持せず、このプライベートメソッドから必ず情報を取得するメソッドもあるようです。
このように各メソッドに静的変数を準備した理由となりそうな注釈箇所をコード内のコメントで見つけました。

「Used to prevent unnecessary calls to _getFilePointer()」、訳すと「_getFilePointer の不要な呼び出しを防ぐのに使われていた」ということになります。現在も使用している静的変数ですので、純粋に「必要以上に呼び出さない為」に準備しているのかもしれません。

ただこのプライベートメソッドは「ファイルポインタを取得する」という処理を抜き出したものですので、read メソッドのように各々で静的変数を保持するようなことをせず、このプライベートメソッドを利用し情報を取得するように動作させるほうが、ポインタ情報の一元管理になりますし、クラス全体の統一性にも繋がるのではないでしょうか。

さてその後の処理の流れとしては、指定するファイル名が正常でありかつ存在しているかどうか、といった確認処理をこのメソッド内で行っているのが分かります。(preg_match, file_exists) それらの確認の後、fopen でファイルをオープンしています。オープンすることで得られたリソースを $filePointers として保持し、その値をファイルポインタ情報として返しています。

これらファイルの存在確認やファイルオープンといった処理に対して問題があった場合、PEAR::raiseError クラスメソッド (*4) を実行することで PEAR エラーオブジェクトを生成しそれを返り値としている処理があります。この一連の流れに注目してください。

このような 「実行」→「確認」→「問題があればエラーを発生させて終了 (return)」というコードの流れは「ガード節」と呼ばれるコーディング手法の1つで、リスト5のように以後の処理を不要に行わせない(ガードする)テクニックです。コードの可読性にも優れるというのも見逃せません。プログラムの書き方手法としてぜひ身につけておきたいところです。

リスト5 ガード節の例

if (!is_numeric($id)) {
  echo 
'ID が数字ではありません。';
  return 
false;
}

//
// 以後行いたい処理内容

その他のファイル操作メソッド

ここまで読み込み処理を行う一連の流れについて読んできました。が、実は読み込み処理を行うメソッドは read だけではないことに既にお気づきでしょう。なにやら名前だけは登場していましたよね。File クラスでは read とは別の読み込みメソッドがまだこれだけ存在しています。くまっち先生

  • ファイルから全ての内容を一気に読み込む readAll
  • ファイルから一行を読み込む readLine
  • ファイルから 1 バイトを読み込む readChar

しかしこれらは「データの読み込む量を限定した読み込みメソッド」と言ってもよいでしょう。事実、実際にこのメソッドたちのコードを見てみてください。若干の違いはあれど、基本的な処理フローは似たものがあるのがお分かりでしょうか。このように似たような機能ではあるものの、別途需要のある(良く使われる)限定的な処理内容を別メソッドとして準備することでライブラリの使い勝手をよくすることもあります。

さて、ここまでデータの読み込み処理を行うコードを読んできました。File クラスには読み込みに対して書き込み処理を行うメソッドも当然準備されています。

今回はここでは改めてコードを示しませんが、基本は読み込み処理と同様、ファイル名に対するファイルポインタ情報を取得し、今度は書き込み処理を行うコードになっています。ここまで読み込み処理を行うコードを読んできた皆さんならば、類似点および相違点がすぐに分かるはずです。確認してみてください。

----

*2)
http://pear.php.net/manual/ja/standards.naming.php

*3)
http://pear.php.net/manual/ja/core.pear.pear.getstaticproperty.php

*4)
http://pear.php.net/manual/ja/core.pear.pear.raiseerror.php

  • 1
  • 2
  • くまっち先生

本名:熊倉 洋介 株式会社アイサイト所属

電子、ネットワーク技術を経て現在のWebアプリケーション開発の世界へ。システム設計およびコーディングがメインで、趣味の範囲内を仕事として行うことができることに感謝しながら過ごす日々。関西を中心に、勉強会やセミナーといった PHP 技術者向けコミュニティで活動を続けており、現在はPiece Frameworkプロダクトへコミットメント中。

ご意見・感想フォーム

今回の「くまっち先生のPEAR講座」への評価・ご意見があればご記入下さい。

評価:
ご意見・感想:

  



Pick Up Q&A

Q
array_mergeの再帰処理の動作について
 このエントリーをはてなブックマークに追加 
A
>1個になったとき$leftを返しますが、 >このとき、最終的な$leftはnullになるかと思います。 いいえ、最後は「渡された配列をそのまま」返します。要素が2以上あるときとの違いは(並べ替えずに戻るので...

>>続きを読む

再帰関数は最初の内は混乱しますが、非常に上手く使える場面もいずれ出てきます。これを機会に学んでいけるといいですね。

▲解説者:岡本(アシアル株式会社 教育コーディネーター兼 システムエンジニア)