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

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

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

フォルダ関連のライブラリについてアドバイスしてもらえないでしょうか? phpのフォルダ関連の操作がそのままだと少し面倒な感じがしたので 自分でライブラリのようなものを作りたいと思いました。 ------------------------------------------------------------------------------------------ calss My_Directory { const SIZE_FORMAT_B = 0; const SIZE_FORMAT_KB = 1; const SIZE_FORMAT_MB = 2; const SIZE_FORMAT_GB = 3; // フォルダへのパスを指定してオブジェクトを作成。 __construct($dir_path); // フォルダのサイズを取得。$recursiveがtrueで再帰的に全階層のファイルを調べる。 getSize($recursive = true, $sizeFormat = self::SIZE_FORMAT_B, $round = 2); // フォルダの削除。中に入っているファイルも削除される。 delete(); // フォルダに入っているファイル名を取得。$recursiveがtrueで再帰的に全階層のファイル名を取得。 // その場合、配列の配列形式にする。 getFileNames($recursive = true); } $path = 'C:\myfolder';// ローカル環境 $dir_obj = new My_Directory($path); echo $dir_obj->getSize(true, My_Directory::SIZE_FORMAT_MB, 1).'MB';// 例えば、「22.3MB」と表示される print_r($dir_obj->getFileNames()); /*例えば、 Array ( [0] => file_1 [1] => file_2 [2] => file_3 [sub_dir] => Array ( [0] => sub_dir_file_1 [1] => sub_dir_file_2 [sub_sub_dir] => Array ( [0] => sub_sub_dir_file_1 ) ) ) でも結局foreachのループで再帰的に調べることになるから、やっぱりめんどうだなぁ・・・ */ $dir_obj->delete();// myfolderが削除される ------------------------------------------------------------------------------------------ ただ、deleteした後にgetSizeとか実行した場合に、 例外を投げればいいのかなぁと考えたりしたのですが、 そもそもオブジェクトにして扱うこと自体が適切なのかどうか? だからフォルダ関連のライブラリがあまり存在しないのかなと思ったりしたのですが、 今回のようにライブラリを作ることに対してのアドバイス(自分ならこうするとか、ここはそんな風にやらないとか) など些細なこともでいいので教えてもらいたいです。

  • PHP
  • 回答数10
  • ありがとう数11

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

  • ベストアンサー
回答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

  • PHP初心者 再帰処理について

    あるフォルダ以下に含まれる全てのフォルダ名をフルパスですべて列挙するという処理を描こうと下記のブログを参考にして自分で少し書き換えたのですが、うまくいきません。 http://blog.asial.co.jp/12 <参考にした部分> function getFileList($dir) { $files = scandir($dir); $files = array_filter($files, function ($file) { // 注(1) return !in_array($file, array('.', '..')); }); $list = array(); foreach ($files as $file) { $fullpath = rtrim($dir, '/') . '/' . $file; // 注(2) if (is_file($fullpath)) { $list[] = $fullpath; } if (is_dir($fullpath)) { $list = array_merge($list, getFileList($fullpath)); } } return $list; } </参考にした部分> <自分で変更したコード> function getFileList($dir) { $files = scandir($dir); $files = array_filter($files, function ($file) { // 注(1) return !in_array($file, array('.', '..')); }); $list = array(); foreach ($files as $file) { $fullpath = rtrim($dir, '/') . '/' . $file; if (is_dir($fullpath)) { $list[] = $fullpath; $list[] = array_merge($list, getFileList($fullpath)); } } return $list; } </自分で変更したコード> 変更といってもis_fileの部分の削除と$list[] = $fullpath;を追加しただけなのですが、「~ bytes exhausted」というエラーになってしまいます。 再帰関数が内部的にどういう処理をしているのかよくわかってないので、正直変更したコードがどういう動きをしているのかいまいち理解できません。参考書にある再帰関数は腑に落ちないながらも結果としてはそうなるということは理解しました。 あとそれ以前に $files = array_filter($files, function ($file) {   return !in_array($file, array('.', '..')); の部分がわかりません。 scandirの戻り値には要素の最初の方に「.」と「..」が付くのでそれを削除する目的だとブログにはありますが、in_arrayはただ第一引数のものを第二引数から検索するだけのはずなのに、$filesの中身をarray_filtersの処理後に確認してみるとちゃんと「.」と「..」が削除されていて不思議です。あとin_arrayは第一引数のものを第二引数の中から検索するという関数だと思いますが、なぜそれをわざわざ反転させて((array('.', '..'), $file);じゃなく($file, array('.', '..'));)!in_arrayとしてるんでしょうか? *ちなみに引用したブログのコードの動作は確認済みで元のコードは完全に正しいです。引用したコードに文句をつけているわけではなく自分がわかっていないだけです。(^^ゞ 以上です。よろしくお願いします。

    • ベストアンサー
    • PHP
  • サブフォルダ内のフォルダ名取得

    連続処理のため、特定フォルダ以下のフォルダ名全てを取得する必要があります。 そこで本に書いてあったコードを試してみたのですが、フォルダ以下のサブフォルダまでしか取得できませんでした。 サブフォルダ以下にもフォルダがあるのですが、どのようにして取得すればいいのでしょうか? ↓以下が試してみてコードになります With CreateObject("Scripting.FileSystemObject")  With .getfolder(Start_Path)   For Each Obj_Folder In .subfolders    WorkSheets.Cells(i, 2).Value = Obj_Folder.name    i = i + 1   Next Obj_Folder  End With End With

  • EXCEL フォルダだけを検索したい

    EXCEL2003を使っています。 開いているファイルと同じフォルダ内に「テストフォルダ」があるかどうかを調べ、存在した場合に削除したいのですが、以下のような書き方ではフォルダだけでなくファイルも検索してしまうようです。 フォルダだけを検索するにはどうしたらいいでしょうか? FSOでできることは分かっていますが、以下の方法で試してみたいのです。どうぞ宜しくお願い致します。 Sub test() my_path = ActiveWorkbook.Path & "\" f_name = Dir(my_path, 16) Do Until f_name = "" If f_name = "テストフォルダ" Then RmDir "テストフォルダ" End If f_name = Dir() Loop End Sub

  • フォルダの中身がカラか調べる

    vbaです。 フォルダ(新しいフォルダ)を作り、その中にサブフォルダ(Test用フォルダ)を作って --------------------------------------------------------- Sub フォルダの中身がカラか調べる() If Dir("D:\新しいフォルダ\Test用フォルダ\*.*") = "" Then MsgBox "カラです" Else MsgBox "カラではありません" End If End Sub --------------------------------------------------------- を実行すると、新しいフォルダの中にフォルダがあるのに、 「カラです」が表示されてしまいます。 新しいフォルダのファイルサイズは0です。 If Dir("D:\新しいフォルダ\Test用フォルダ\*.*") = "" Then のコードは、フォルダの中のファイル数ではなく、 フォルダのサイズを取得してしまうのでしょうか?

  • サブフォルダ内の全てのテキストファイルを1発処理する方法

    Excel2007のVBAを使い、下記のようなマクロを作成しました。 (質問に必要そうな所だけ掲載しています。) Dim dir_name As String ' ディレクトリ名 Dim file_name As String ' ファイル名 Dim EffectiveRow As Integer ' 開始行数/Excel/Row(行) Dim ShellApp As Object ' SHDOCVW.DLL / MIC Dim oFolder As Object ' フォルダパス EffectiveRow = Range("A65536").End(xlUp).Row Set ShellApp = CreateObject("Shell.Application") Set oFolder = ShellApp.BrowseForFolder(0, "フォルダ選択", 1) dir_name = oFolder.items.Item.Path ChDir dir_name file_name = Dir("*.txt", vbNormal) Do Until file_name = "" EffectiveRow = EffectiveRow + 1 Call ImportText(file_name, EffectiveRow) file_name = Dir() Loop ShellApp.BrowseForFolderを使い、指定したフォルダを選択すると、 その中に有る、テキストファイル(.txt)を、全てExcelに書き込む というマクロを作成したのですが、もっと汎用性を高くするために、 下記の内容を実現したく思っています。 - ↓ 実現したい事↓ - - 状況 - *フォルダの中に、サブフォルダが複数有り、そのサブフォルダの中に、 テキストファイル(.txt)が複数入っている。 - 処理 - サブフォルダを格納している*フォルダを、ShellApp.BrowseForFolderで 選択し、一度でサブフォルダ内のテキストファイルを全てExcelに書き込 めるようにしたい。 上記のマクロから発展させて、このような処理を行う事は出来るでしょうか? また、どのようにすれば実現させることが出来るでしょうか? ご教授のほど、よろしくお願いします。m(_ _)m ※ [*フォルダ ] は同一フォルダです。

  • サブフォルダの親フォルダを変えたい

    フォルダの中のサブフォルダを取得してくて、 http://officetanaka.net/excel/vba/tips/tips95.htm の --------------------------------------------------------- Sub Sample4() Dim buf As String, msg As String buf = Dir("*.*", vbDirectory) Do While buf <> "" If InStr(buf, ".") = 0 Then msg = msg & buf & vbCrLf buf = Dir() Loop MsgBox msg End Sub --------------------------------------------------------- をやってみたら、サブフォルダを取得できたのですが、 上記のコードを実行すると 元々のフォルダのパスが「C:\Users」で、 「C:\Users」のサブフォルダが取得されてしまいます。 でも上記のコードでは、「C:\Users」は指定してないと思うのですが、 なぜ「C:\Users」のサブフォルダが取得されてしまうのでしょうか? 例えば 「C:\Users」ではなく、「C:\Program Files」のサブフォルダを取得するには、 どのようにコードを書き換えればいいのでしょうか? ご教授よろしくお願いします。

  • RmDirでフォルダが削除できない vba

    http://www.k1simplify.com/vba/tipsleaf/dir.html を参考にしたのですが Sub test() RmDir "\\test-PC\Users\Public\test" End Sub でフォルダの削除ができると思ったのですが パス名が無効ですというエラーになってしまいます。 ネットワークパスだからダメなのでしょうか? パスはフォルダからコピペしたので間違いないです。

  • PHP 変数 aタグで囲いたい

    失礼します。echo の中の変数をaタグで囲いたいのですがやり方がわかりません。 よろしくお願いします。 foreach($files as $file_path => $file_info) { if (!$file_info->isFile()) { continue; } echo 'file path : ' .$file_path ."</br>"; echo 'file size : '. $file_info->getSize() ."</br>"; echo 'contents : '. file_get_contents($file_path) ."</br>"; }

    • ベストアンサー
    • PHP
  • vbaでフォルダの中のファイルを削除したい

    vbaでフォルダの中のファイルを削除したいのですが その場合は、 Sub フォルダの中身を全て削除する() Set myFSO = CreateObject("Scripting.FileSystemObject") With myFSO MyFolderName = ConsT_フォルダ名 & "\" MyFileName = Dir(MyFolderName & "\*.*") Do While MyFileName <> "" myFSO.DeleteFile MyFolderName & "\" & MyFileName MyFileName = Dir() Loop End With Set myFSO = Nothing End Sub の様にして、一つ一つループして消していかないとダメでしょうか? フォルダは残して、カラのフォルダにしたいです。

  • フォルダの属性について 別途

    MediaWiki1.2でサイト作成中です。 画像(test.jpg)をアップロードするとフォルダが2つ自動作成されます。 例:サイトルート/images/5/2a/test.jpg imagesフォルダはデフォルトで存在するもので、「5」「2a」が自動で作成されます。 前回、「5」「2a」のフォルダのパーミッションが644になって不具合が出てしまうので質問しました。 chmodを利用すると、「2a」フォルダだけは777にすることはできました。 ディレクトリ作成と思われるソース抜粋は以下の通り。 /** * Make directory, and make all parent directories if they don't exist * * @param $dir String: full path to directory to create * @param $mode Integer: chmod value to use, default is $wgDirectoryMode * @param $caller String: optional caller param for debugging. * @return bool */ function wfMkdirParents( $dir, $mode = 0777, $caller = null ) { global $wgDirectoryMode; if ( FileBackend::isStoragePath( $dir ) ) { // sanity throw new MWException( __FUNCTION__ . " given storage path '$dir'." ); } if ( !is_null( $caller ) ) { wfDebug( "$caller: called wfMkdirParents($dir)\n" ); } if( strval( $dir ) === '' || file_exists( $dir ) ) { return true; } $dir = str_replace( array( '\\', '/' ), DIRECTORY_SEPARATOR, $dir ); if ( is_null( $mode ) ) { $mode = $wgDirectoryMode; } // Turn off the normal warning, we're doing our own below wfSuppressWarnings(); $ok = mkdir( $dir, $mode, true ); // PHP5 <3 chmod($dir,0777); wfRestoreWarnings(); if( !$ok ) { // PHP doesn't report the path in its warning message, so add our own to aid in diagnosis. trigger_error( sprintf( "%s: failed to mkdir \"%s\" mode 0%o", __FUNCTION__, $dir, $mode ), E_USER_WARNING ); } return $ok; chmod($dir,0777); } ※chmodの使用タイミングが理解未熟なので、2か所に登場しています。 「$dir」はフルパスなんですが、上記方法だと「2a」だけ777になって「5」フォルダは777にならないのです。 そこで、 「$dir」のひとつ上の階層(最下層のひとつ上になります)のフォルダのパーミッションを指定して777にしたいのですが、どのようにすればよいのでしょうか。上記例の場合、「5」フォルダの名称は自動生成なので「../5」のようにソースに書けなくて困っています。

    • ベストアンサー
    • PHP

専門家に質問してみよう