2

だから....私はファイルが書き込まれたかどうかを返す小さな関数と、そうでない理由を書いていました....次のようなものです。

array (
    'success' => false,               // easy, by checking function result
    'reason' => 'Permission denied'   // how am I supposed to find this???
)

何かが足りないかもしれませんが、ファイルの保存に失敗したときのエラーメッセージをキャプチャする方法が見つからないようです。

私が最初に思いついたのは、出力バッファリングを使用してエラーをキャプチャすることですが、それは途方もなく範囲外であり、エラーが発生しやすく、巨大なハックです(つまり、別のタイプのエラーが干渉する可能性があります)。

file_put_contents通常、これは、f*関数が例外をスローしないことを除いて、OOPスタイルの例外処理に適しています。

それSplFileObjectは仕事をしているようです...1つの例外を除いて。これは行ベースのクラスであり、バイナリファイルの読み取りには適していません

助言がありますか?

PS:怠惰と呼んでください、しかし私のコードがすべての例外的なケース(書き込み許可、アクセスできないドライブ、間違ったパスなど)をチェックするべきだとは思いません。

4

2 に答える 2

2

あなたが提案していることは、表面上は正しいように聞こえますが、ファイルシステムにファイルを書き込む基本的な操作を実行する包括的な API を持っています。ただし、PHP 開発者は、アプリケーションのニーズに合わせて機能する API をまとめることを私たちに任せていると思います。彼らは自分たちでそれを行うための基本コンポーネントを提供してくれるからです。

File::write以下は、ファイル書き込み操作に使用する方法のスニペットです。

$fileInfo = new SplFileInfo($fileUri);

if (!is_dir($fileInfo->getPath())) {
    // I have some proprietary stuff here but you get the idea        
}

$file = new SplFileObject($fileUri, $mode);

if (!$file->flock(LOCK_EX | LOCK_NB)) {
    throw new Exception(sprintf('Unable to obtain lock on file: (%s)', $fileUri));
} 

elseif (!$file->fwrite($content)) {
    throw new Exception(sprintf('Unable to write content to file: (%s)... to (%s)', substr($content,0,25), $fileUri));
}

elseif (!$file->flock(LOCK_UN)) {
    throw new Exception(sprintf('Unable to remove lock on file: (%s)', $fileUri));
}

elseif (!@chmod($fileUri, $filePerms)) {
    throw new Exception(sprintf('Unable to chmod: (%s) to (%s)', $fileUri, $filePerms));
}

これらは、テストできるエッジ ケースのほんの数例です。「ドライブが接続されている」かどうかをテストする必要がある場合は、is_writableを呼び出します。したがって、それをチェックのリストに追加して、アプリケーションにとって意味のあるメッセージで応答することができます。

次に、上記のエラーをログに記録したい場合は、呼び出しコードを try/catch ブロックでラップするだけです。

try {
    File::write($fileUri);
} catch (Exception $e) {
    error_log($e->getMessage);
}
于 2012-05-02T00:19:17.490 に答える
1

アップデート

@hakre がいいアイデアをくれました。私のシステムと矛盾するのは、デフォルトの FS 実装です。

これを解決する方法は、プロトコルのデフォルト ストリーム ラッパーの登録を解除し、file://実際に例外をスローする独自のストリーム ラッパーを登録することです。これにより、例外を自由に使用file_put_contents()し、同時にキャッチすることができます。

ああ、カスタム ストリーム ラッパーも (ロックを強制することで) アトミックであることを確認できます。


これが私がこれまでに思いついたものです。もちろん、実際の FS チェック (ドライブ/パスの存在、権限など) が必要です。

    /**
     * Save file to source DSN.
     * @return boolean True on success, false on failure (see last_error for details). 
     */
    public function save(){
        $file = fopen($this->source, 'wb');
        if(!$file){
            $this->_last_error = 'Could not open file stream';
            return false;
        }
        if(!flock($file, LOCK_EX)){
            $this->_last_error = 'Could not lock file for writing';
            return false;
        }
        if(!ftruncate($file, 0)){
            $this->_last_error = 'Could not clear file';
            return false;
        }
        if(fwrite($file, $this->contents)===null){
            $this->_last_error = 'Could not write to file';
            return false;
        }
        if(!fflush($file)){
            $this->_last_error = 'Could not flush to file';
            return false;
        }
        if(!flock($file, LOCK_UN)){
            $this->_last_error = 'Could not unlock file';
            return false;
        }
        if(!fclose($file)){
            $this->_last_error = 'Could not close file';
            return false;
        }
        return true;
    }

それ非常に冗長で、私が望んでいたものとはまったく異なります。FS チェックを使用すると、これはおそらくかなり増加します。

file_get_contents()最初から正しくコーディングされていれば、このすべてのコードが実現できたのに残念です。

于 2012-05-02T00:31:11.167 に答える