• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:フォルダ関連のライブラリについてアドバイスしてもらえないでしょうか?)

フォルダ関連のライブラリについてアドバイスしてもらえないでしょうか?

このQ&Aのポイント
  • フォルダ関連のライブラリについて、自作する際の注意点やオブジェクト指向の利用方法について教えてください。
  • フォルダ関連の操作が面倒な場合、自分でライブラリのようなものを作ることができます。ただし、オブジェクト指向を適切に利用する必要があります。
  • フォルダ関連の操作には、ファイルのサイズ取得や削除などがあります。これらの操作をライブラリにまとめてソースコードを管理することで、効率的に開発を進めることができます。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.7

<?php interface Lib_Directory{ public function getPath(); public function isDir(); public function isFile(); } class Lib_Folder implements Iterator, Lib_Directory{ private $path = null; private $resource = null; private $count = -1; public function __construct($dir){ if(!is_dir($dir)){ throw new Exception("test"); } $dir = realpath($dir); $this->path = $dir; $this->resource = opendir($dir); if(!$this->resource) throw new Exception("test2"); } public function getPath(){ return $this->path; } public function getBase(){ return basename($this->path); } public function isDir(){ return true; } public function isFile(){ return false; } public function rewind(){ rewinddir($this->resource); $this->count = -1; $this->current = $this->get(); } public function current(){ return $this->current; } public function next(){ $this->current = $this->get(); return $this->current; } public function valid(){ return $this->current === false ? false : true; } public function key(){ return $this->count; } private function get(){ while(($data = readdir($this->resource)) !== false){ if($data == "." || $data == "..") continue; break; } if($data === false){ return false; } $this->count++; $data = $this->path . DIRECTORY_SEPARATOR . $data; if(is_dir($data)){ $obj = new self($data); }else{ $obj = new Lib_File($data); } return $obj; } } class Lib_File implements Lib_Directory{ private $path = null; public function __construct($path){ if(is_dir($path)) throw new Exception("test3"); $path = realpath($path); $this->path = $path; } public function getPath(){ return $this->path; } public function getBase(){ return basename($this->path); } public function isDir(){ return false; } public function isFile(){ return true; } } echo "<pre>"; toArray('../cpn', $ret); print_r($ret); echo "</pre>"; functi

その他の回答 (9)

回答No.10

RecursiveIteratorIteratorなど、Iterator群は、情報が薄いので情報を開いてみたことがなかったんですが、(Iteratorは結構使いますが) 実際マニュアル見ても、やっぱり情報が薄くてよくわかりませんね。 interface Zend_Directory_Interface { public function getSize(); public function delete(); } interface Zend_Iterator_Directory_Interface { public function getPath(); public function isDir(); public function isFile(); } は、Zend_Iterator_Directory_Interfaceに分ける必要がないと思います。 上記に配置しているメソッドはとくにIterationに関係ある項目ではないので。 上記は、Zend_Directory_Interfaceに集約してしまって良いのではないですか。 Zend_Directory_Folderには、これに加えて、Iteratorインターフェイスを実装してやれば。 で、もし、RecureserveIteratorIteratorを使うなら、恐らく、 http://www.php.net/manual/ja/class.recursiveiterator.php こちらの、RecursiveIteratorを実装する必要がありそうですね。 class xxx_Folder implements RecursiveIterator{ public function getChildren(){ return $this->current(); //で恐らくいいのかな。多分。 } public function hasChildren(){ $obj = $this->current(); return !$obj->isFile(); } //以下は前回私の書いた実装 } もし、Folder自体にIteratorインターフェイスを実装しないなら、 class xxx_Folder implements IteratorAggregate{ public function getIterator(){ //後は、RecureserveIteratorIteratorなりをreturnすれば良いと。 } } とりあえず私は無計画に作っては消して作っては消してといつもつくっちゃうので、今ぱっぱとベストだ、といえる実装は思いつきませんが、何度か色々なプロトタイプ作って消して、マージしていけば良いのではないでしょうか。

takagoo100
質問者

お礼

ご回答ありがとうございます。 なるほど、いくつか選択肢がありそうですね。 自分もこれからIterator群を研究してみて、 いろいろ試してから作成に繋げていきたいと思います。 いろいろ参考になりました。ありがとうございます。

回答No.9

どうしてもZend_Iterator_Directoryとかがアレだということであれば、 Zend_Directory_Directory(またはFolder) Zend_Directory_Fileなどとしてもよいわけで。 また、別々のディレクトリに切り分けることに違和感があるとのことですが、 Zend_Formは、Zend_Form_Elementが、Zend_Validate_Interface継承オブジェクトだったりしてます。 Zend_Service_***系統も、内容はといえば、Zend_Http_Clientに各パラメータを振り分けて通信させてレスポンスを返します。 そう考えれば、Fileクラスにファイル名を渡せばファイルを処理することが出来るわけですから、別の切り分け方をしても何ら問題はない気がします。 尚、もし、私がライブラリの開発をするなら、Zendというプリフィックスは使わないと思います。 私はZendのライブラリ制作者ではないので。 もしやるなら ・PEARやOpenPearのなかで近いライブラリのもののプリフィックスをつける ・全然関係ない名称を使う(Moochy、Doctrine、Smartyなどのような固有名詞的なものとか) といったところでしょうか。

takagoo100
質問者

お礼

ご回答ありがとうございます。 たしかにZendに追加するってのはおかしいですよね。 とりあえず今はこの形でやっていきたいのですが、 Zend_Iteratorフォルダには Zend_Iterator_Directory_FolderやZend_Iterator_Directory_Interfaceやhttp://www.php.net/manual/ja/spl.iterators.phpでいう RecursiveIteratorIteratorやRegexIteratorなどのイテレーター群を配置して、 Zend_Directoryフォルダには Zend_Directory_FolderやZend_Directory_FileやZend_Directory_Interfaceなどを配置したいと思ってますが、 Zend_Directory_Fileは interface Zend_Directory_Interface { public function getSize(); public function delete(); } interface Zend_Iterator_Directory_Interface { public function getPath(); public function isDir(); public function isFile(); } class Zend_Directory_File implements Zend_Directory_Interface, Zend_Iterator_Directory_Interface { protected $path = null; public function __construct($path); public function delete(); public function getSize(); public function getPath(); public function isDir(); public function isFile(); } というふうに2つのインターフェイスを継承させるように考えているのですが、 これは変(あまり適切ではないとか)でしょうか? 他には class Zend_Directory_Folder implements Zend_Directory_Interface { protected $path = null; public function __construct($path); public function delete(); public function getSize(); public function getIterator();//RecursiveIteratorIteratorのようなものを返すのが良さげに思えるのですがどうでしょうか? } class Zend_Iterator_Directory_Folder implements Iterator, Zend_Iterator_Directory_Interface { protected $path = null; public function __construct($path); public function getPath(); public function isDir(); public function isFile(); } Zend_Directory_FolderのgetIterator()に当たるメソッドは、 本来フォルダの中身を再帰的に全て配列などで返そうか考えていたのですが、 深さ(getDepth())などの情報も一緒に付ける必要があると思ったので、 やっぱり再帰的な構造になっているオブジェクトなどを返した方がいいと思いました。 コンセプトとしては、Zend_Directory_Folderというのはパスさえ渡せば、 削除もできるし、サイズを取得することもできるし、中にあるファイルを全て取得することも簡単にできるし、 フォルダを扱うことに関して1つのクラスでできるようにというコンセプトです。なので中にあるファイルの取得などは RecursiveIteratorIteratorなどでもできるのですが、それをZend_Directory_FolderのgetIteratorメソッドで 返してあげる形で1つのクラスでということなのですが、これも何かおかしなところがあればアドバイス頂けないでしょうか?

回答No.8

一応作ってみたので、下記に書き込んでみました。 途中で切れているのは、ディレクトリ構造を配列に直して出力してテストするだけなので 無視してかまいません。 とりあえず見てみてください。

takagoo100
質問者

お礼

ご回答ありがとうございます。 なるほど、isFile,isFolderは両方のオブジェクトがはきだされてきても判別できるように それぞれのクラスでtrue,falseを設定しておくようにするわけですね。 Zendに配置する場合にどのような構成、ファイル名にしようかずっと考えていたのですが、 同じZend_Iterator_Directory(Lib_Directory)インターフェイスをimplementsしているのに 例えば Zend_Iterator_Folder Zend_Control_File とそれぞれ分けて別々のフォルダに配置してあるのはおかしくないですか? かといって、 Zend_Iterator_Directory_File(Lib_File)はiteratorっていうわけでもないですよね・・・ http://www.php.net/manual/ja/spl.iterators.php にたくさんあるように、作るならZend_Iteratorというフォルダを配置してそこに Zend_Iterator_Folderはやっぱり置きたいですよね? だけど同じインターフェイスをimplementsしているZend_Iterator_Directory_File(Lib_File) だけ別のフォルダにあるの気持ち悪いというか・・・ 最後はもちろん自分で最終決定しなければいけないのですが、 申し訳ないのですが、もう一度hogehoge78さんの配置構成や基本的なお考えを教えて頂けないでしょうか?

回答No.6

ディレクトリと、フォルダは、ほぼ等価の意味を持っていますが、 今回、カレントのディレクトリを指定した時の中の情報として、フォルダを扱うクラスとファイルを扱うクラスがありますので、まぁ、大きな分類としてディレクトリ操作一般を扱うものの中の、フォルダのみを扱うものとファイルのみを扱うものという意味で、ディレクトリ、という分類の中にフォルダとファイルとしただけだったんですが、気持ち悪ければ、また別の場所にすれば良いと思います。 Zend_Iterator_Folder Zend_Control_File とか。 フォルダという言葉が気持ち悪ければ Zend_Iterator_Directory_Directoryとか。 そこら辺のセンスはまた別に必要になりますし、私はあまりセンスのある方ではないので、よくわかりません。 Zend_Iterator_Directoryインターフェイスは、とりあえずそのカテゴリに存在するフォルダクラスとファイルクラスの共通項なので、今パッと思いつくのは、 ・getPath ・delete等操作をするクラス ・isFile(またはisDirとか) じゃないですかね。最終的にforeachでまわして一つづつ取得していったときに、両方に実装されていないと困るメソッドをインターフェイスで縛りを入れてやるというモノになります。 また、質問者さんの記述したクラスの内容で問題なさそうですが インスタンスでは、opendir関数が吐き出すリソースを受け取るだけにして、 nextやcurrentで、ポインタを一つすすめるようにしたほうが良いのではないですか。 class XXXXX{ protected $res = null; public function __construct($path){ $this->res = opendir($path); if(!$this->res) throw new Exception("can not read"); } protected $tmp = null; public function next(){ $this->tmp = readdir($this->res); } public function current(){ return $this->tmp; } public function __destruct(){ closedir($this->res); } } とか。

takagoo100
質問者

お礼

ご回答ありがとうございます。 すいません、ここにきて自分の中で考えが混乱してきまして とりあえずFileの方は、Zend_Iterator_Fileでやっていくように統一してもえらないでしょうか? Fileはclass Zend_Iterator_Directory_File implements Zend_Iterator_Directory Folderはclass Zend_Iterator_Directory_Folder implements Iterator, Zend_Iterator_Directory とした場合に、いくつかというかかなり質問があるのですが、 まず FolderはIteratorをimplementsしているのですが、 FileはIteratorをimplementsしなくていいのでしょうか? hogehoge78さんが提示されたclass XXXXX は 自分の例でいうZend_Iterator_Directory_Folderのことでしょうか? もしそうだとしたら、どこでZend_Iterator_Directory_Fileをnew(生成)すれば良いのでしょうか?そのメソッド自体を具体的に見せてもらえないでしょうか? それとフォルダの中にある'.'や'..'はどういう扱い(例えばクラスにするとか)になるのでしょうか? Zend_Iterator_Directoryインターフェイスの isFlie()というのがよく分からないのですが、 例えばZend_Iterator_Directory_Fileはそもそもファイルを扱っている(想定している)ので 絶対にファイル(isFlie()==true)にならないですか? 自分の中でフォルダもファイルの一種とかちょっともう混乱してきてるというか・・・頭の中で整理ができない状況です・・・ 自分が考え途中のスクリプト(文字数の関係で補足を参照してください)に 具体的に追加して書き加えたり、あるいは全く新しくでも結構ですので クラスの例を書いて頂けないでしょうか?

takagoo100
質問者

補足

interface Zend_Iterator_Directory { public function getPath(); public function isFlie(); } class Zend_Iterator_Directory_File implements Zend_Iterator_Directory { protected $path = null; public function __construct($path) { $this->path = $path; } public function isFile() { return is_file($this->path); } public function getPath() { return $this->path; } } class Zend_Iterator_Directory_Folder implements Iterator, Zend_Iterator_Directory { protected $position = 0; protected $res = null; public function __construct($path) { $this->path = $path; $this->res = opendir($path); if(!$this->res) throw new Exception("can not read"); } protected $tmp = null; public function rewind() { $this->position = 0; } public function current() { return $this->tmp; } public function key() { return $this->position; } public function next() { $this->tmp = readdir($this->res); ++$this->position; } public function valid() { return isset($this->tmp); } public function __destruct() { closedir($this->res); } public function isFile() { return is_file($this->current()); } public function getPath() { return $this->path; } }

回答No.5

Zend/Iterator/Directory/File とした場合に、私がFileに記述する内容は、 単純にファイルの構造が記述されているようなものですかね。 (getSizeメソッドとかそういうもの。) Iteratorじゃないので、そこに記述するのが気持ち悪いなら、まぁ Zend/File とか、そういう感じになるんじゃないですかね? ラッパークラスのほうは、たとえば、単純に「再帰的にルート以下のディレクトリ構成を配列にしたい」とかなら、 Zend/Directory/Treeとか Zend/Tree/Directoryとか なんかそういう感じのものにすればいいんじゃないのかなぁとか。(これも実際どうだろうなぁ。) Zend_Iterator_Directory_Folderと Zend_Iterator_Directory_Fileは Zend_Iterator_Directoryインターフェイスを継承したクラス、とかにする感じですかね。 Floderのほうは、自身の持っているファイルやフォルダを順繰りに取得が出来て、Fileのほうは、ファイルの詳細情報が表示できるようなものと考えました。 で、既存のDirectoryIteratorは、ディレクトリのイテレータなので、フォルダとファイルが両方混ざって吐き出されてくるし、再帰的に何かやるときには、ディレクトリの名称なのであればそこで再度new DirectoryIteratorしてやらないといけないし(RecursiveDirectoryIteratorというのもあるようですけど) 質問者さんが目指したい方向と違いがあったりしませんか。 (しないのであれば素直にDirectoryIteratorを使うべきですが) また、deleteメソッドを実装するとしてましたが、これも、Iterator_Directoryは、閲覧のみとして、操作関連に関しては、Zend_Control_Directoryとか別のオブジェクトで操作させるという方法でもいい気がします。 まぁ、お急ぎでないのであれば、ネーミングとかディレクトリ構成とかそういうのは全部おいておいて 仮のネーミング等で実装したい機能とか全部つめたクラスを作り上げてから、リファクタリングとかするほうがいい気がします。

takagoo100
質問者

お礼

ご回答ありがとうございます。 自分でこの困り度で質問しておいて言うのもなんですが、 もしそちらが宜しければ、もう少し自分がある程度理解できるようになるまで アドバイスをして頂ければうれしいと思います。 一応自分なりの理解でイテレータの方を作成(文字数の関係で補足を参照してください)してみたのですが、 こんな感じで宜しいでしょうか? ただZend_Iterator_Directoryインターフェイスに何を記述すればよいのかが いまいち分かりません・・・ それと今までDirectoryとFolderを同じようなものだと思ってたのですが、 今ではなんとなく違いをイメージはできるのですが、具体的に説明となると・・・ hogehoge78さんのお考えを教えてもらえないでしょうか?

takagoo100
質問者

補足

interface Zend_Iterator_Directory { // Zend_Iterator_Directory_FolderにもZend_Iterator_Directory_Fileにも共通する // メソッドなどを記述すると思いますが、具体的にそれはなんでしょうか? } class Zend_Iterator_Directory_File implements Zend_Iterator_Directory { protected $path = null; public function __construct($path) { $this->path = $path; } public function isFile() { return is_file($this->path); } public function getSize() { return filesize($this->path); } public function getPath() { return $this->path; } } class Zend_Iterator_Directory_Folder implements Iterator, Zend_Iterator_Directory { private $position = 0; private $array = array(); public function __construct($path) { $this->read($path); } public function rewind() { $this->position = 0; } public function current() { return $this->array[$this->position]; } public function key() { return $this->position; } public function next() { ++$this->position; } public function valid() { return isset($this->array[$this->position]); } protected function read($path) { if (false === ($dir = @opendir($path))) { throw new Exception('open error'); } while (false !== ($item = readdir($dir))) { if ($item === '.' || $item === '..') { continue; } $tmpPath = $path . '\\' . $item; $this->array[] = new Zend_Iterator_Directory_File($tmpPath); if (is_dir($tmpPath)) { $this->read($tmpPath); } } closedir($dir); } } $path = 'C:\myfolder'; $obj = new Zend_Iterator_Directory_Folder($path); foreach($obj as $file) { if ($file->isFile()) { print "file path=" . $file->getPath() . ' size=' . $file->getSize() . "<br>\n"; } else { print "folder path=" . $file->getPath() . "<br>\n"; } }

回答No.4

あ、ラッパークラスの置き場については、 まぁまた別のディレクトリきって配置すればよいと思います。 Zend_Formも、Zend_ValidateとかZend_Decoratorとか組み合わせてますし。

回答No.3

ちょっと私も、英語が苦手で、あまりベストな名前がつけられないので、答えようがないというところなんですけど、 Zendの場合 {Prefix(Zend固定)}_{動詞}_{具体的な名前} という、名前のクラス名になると思います。 で、FolderもFileも、種類が違うだけで同列と考えると Zend_Search_Folder Zend_Search_File とか、なるんですか、ねぇ・・・。自信はないです。 また、デザインパターンとかはあまり私もよく分かっていないので、 $folder->delete(); として、削除して、後は質問者さんがおっしゃってるようにExceptionを返すようにしちゃうのか、私の提案したようにするか、どっちがベストかはちょっと分からないですね。 後は(回答してる最中に思いついた)、 Zend/Iterator とかディレクトリ切っちゃって、その中に Zend_Iterator_Directoryクラスを作って Zend/Iterator/Directory/Folder Zend/Iterator/Directory/File 見たいな感じでぶつぶつきっちゃって、 必要とあらば、 Zend/Iterator/Directory/File/Image とか、ファイルの種類でクラスを分けてごにょごにょするのかとか ふわっと色々思いつきますね。 後は好みとか、Gofなどのデザインパターンとか、そのほかのライブラリ(PEARやZend、PHPの標準ライブラリやフレームワーク)などを見てやってみる、って感じでしょうか。 あまり、具体的な提案が出来なくて申し訳ないです。

takagoo100
質問者

お礼

ご回答ありがとうございます。 ふと思ったのですが、 Zend/Iterator/Directory/File のFileのイテレータのクラスってどんな内容(例えばメソッドとか)なんでしょうか? Zend/Iterator/Directory/Folder のFolderのイテレータのクラスは DirectoryIterator http://jp.php.net/manual/ja/class.directoryiterator.php のような内容になると思いますけど、ただこれもFolderのイテレータのクラスの内容が分からないので Zend_Iterator_Directoryクラスとの違いがまだ自分の中ではっきりしないです・・・。 ラッパークラスはそれぞれ例えば Zend/Directoryフォルダ(名前はやっぱり適切じゃないかなぁ・・・)を作ってその中に Zend_Directory_FileクラスならCakePHPのライブラリにあるようなFileクラスでいいでしょうし Zend_Directory_FolderクラスならCakePHPのライブラリにあるようなFolderクラスや 自分が質問で作成したような内容のクラス(My_Directory)でいいですよね?

takagoo100
質問者

補足

訂正です ×ただこれもFolderのイテレータのクラスの内容が ○ただこれもFileのイテレータのクラスの内容が

回答No.2

CakePHPに、FolderクラスとFileクラスってのがあります。 参考までに一度読んでみてはいかがでしょう。 また、もし自分で作成するとしたら、 Folderクラスと、Fileクラスを分けますかね。(まぁ、上記参考のCakeもそうなってますね) フォルダがもつ属性値と、ファイルがもつ属性値は差異がありますので。 で、Folderクラスは、Iteratorインターフェイスでもimplementしてforeachで回せるようにして、 順番にグルグル回せるようにする、感じですかね。 <?php $folder = new Folder("foldername"); foreach($folder as $file){ if($file->isFile()){ echo $file->size(); } } //もし全部を配列で持ってきたいなら、 print_r($folder->toArray()); とか適当に内部で再帰的にforeachしてまわしてきて全部配列にしてから返すような。 //削除するとき $folder->setDelete(true); unset($folder); //とか、削除フラグを立てた状態で、classをunsetしたときに、__destructでフォルダを削除する処理を入れてやるとか? ?> 外側のイメージとしてはそんな感じでどうでしょう。 マジックメソッドの、__destructと、Iteratorインターフェイスを使ってやればイケそうな感じです。 基本は、全部一つずつのファイルで読む感じで、フォルダも再帰的に読んでくるんじゃなくて、 フォルダクラスの中に、フォルダクラスがあるような形にしてやるイメージです。 で、それぐらいなシンプルな形になっているものをさらに別のクラス作ってラップしてやるなりしていけばいいんじゃないでしょうか。

takagoo100
質問者

お礼

ご回答ありがとうございます。 CakePHPは使ったことがあるのですが、そのライブラリの存在は知りませんでした。 結構考えた方が似てたので驚きました・・・(というか違いようがないか) hogehoge78さんの考えだと、そのラッパークラスが所有している$folderオブジェクト をdeleteメソッドの中で $folder->setDelete(true); unset($folder); と記述するのでしょうか? それともフォルダの削除はdeleteメソッドでは行わないのでしょうか? 自分もフォルダ削除後にオブジェクトが残ってるのはおかしいかなと思ってるので deleteメソッドで削除するやり方はどうなのかなぁと。 それともしこのライブラリをzend frameworkに拡張として追加するとしたら どのようなファイル構造にすれば適切だと思いますか? 自分としては、 「Folder(それかDirectory、どちらの名前が適切なんだろう・・?)」という名前のフォルダを作りその中に Folderフォルダ File.php(ファイル関連の機能) Folder.php(フォルダ関連の機能、ラッパークラス) まではいいと思うのですが、hogehoge78さんが仰る ラッパークラスが所有している$folderオブジェクトにあたるクラスを どういうファイル名で配置すればいいのでしょうか?

  • tany180sx
  • ベストアンサー率63% (239/379)
回答No.1

いちお、DirectoryIterator クラスってのはありますよ。

参考URL:
http://jp.php.net/manual/ja/class.directoryiterator.php
takagoo100
質問者

お礼

ご回答ありがとうございます。 なるほどたしかに。 使う側に再帰的な処理は任せる(というかそうするしかない?)という形ですね。 たしかに自分で作ってて $dir_obj->getFileNames() は結局使う側でループ処理しないと駄目ですからね・・・ ただ一方でもっとできるだけ処理はクラス側でお任せしたいというのがあって サイズを取得するにしてもフォルダを削除するにしても できればそちら側でやって欲しいと思ってて、 結局どのような考えでこういうクラスを設計すればいいんだろう・・・

関連するQ&A