PHP で不可能な場合、require メソッドは int を返します
P粉883223328
2023-09-02 09:55:14
<p>いくつかの PHP コードをファイルに保存し、それをロードして再度実行する次のコードがありますが、require メソッドが int を返す場合があります。これはなぜ発生しますか? </p>
<h1>demo.php</h1>
<pre class="brush:php;toolbar:false;"><?php
$f = function() use($a){
$cachePath = '/tmp/t.php';
$code = '<?php';
$code .= "\n\n";
$code .= 'return ' . var_export([], true) . ';';
file_put_contents($cachePath, $code, LOCK_EX);
if (file_exists($cachePath)) {
// 次の行は int を返すことがありますが、なぜですか?
$result = require($cachePath);
if (!is_array($result)) {
var_dump($result, $cachePath, file_get_contents($cachePath));
exit("ok");
}
var_dump($result);
}
};
for($i=0;$i<1000000;$i ) {
$f();
}</pre>
<h1>再現方法は? </h1>
<p>2 つの PHP プロセスを使用して上記のコードを実行します</p>
<pre class="brush:php;toolbar:false;">phpdemo.php</pre></p>
これは
require
の標準の動作であり、include
の動作も同じです:ご覧のとおり、戻り値が上書きされない場合、ハッピー パスでは整数 (1) が返されます。
これはあなたの例では理にかなっています。これまでのところファイルは存在します(したがって致命的なエラーはありません)が、ファイルは作成されたばかりなので、単に切り捨てられているだけ、つまり空である可能性があります。 p>
したがって、戻り値は上書きされず、int(1) が表示されます。
もう 1 つの説明は、当然、整数で上書きしたということです。複数のプロセスが同じファイルに書き込むことができるため、これも可能ですが、例を書いた方法ではその可能性は低くなります。私がこれに言及したのは、それが別の有効な説明だからです。
存在する場合は含む
ファイルが存在するとき (のみ) ではなく、
リーリー$result
を検索するときに競合状態を一時停止する方法の例:その背後にある考え方は、ファイルが存在するかどうかのチェックなどのエラー処理をほとんど行わず、そうでない場合はインクルードできない(include() は警告を発し、それを $result = false で渡すだけ)、そしてその後に行うというものです。 if $result ロードは is_array() テストで機能します。
これはエラーに関するものですが、何を探しているのかはわかっています。つまり、$result は配列です。
これは、トランザクションまたはトランザクション操作と呼ばれることがよくあります。
この新しい例では、$result 配列が空の場合、つまりデータが含まれていない場合には、if-body も入力しません。
プログラム処理レベルでは、これは私たちにとって興味深いかもしれません。ファイルの有無、空であるか空ではない、さらには間違って書き込まれていることさえも、すべて「食べて」$result を無効にする必要があるエラー状態です。
定義エラーは存在しません。
解析エラーの処理 (Include-If-Exists の場合)
PHP 7.0 以降、include() を使用できるようになりました。残念ながら、返されたインクルード ファイルが半分しか書かれていない場合は、PHP 解析エラーが表示され、これを捕捉できます : リーリー
例外をスローする方法/例外処理作業の詳細については、PHP try-catch-finally を参照してください。この例では、assert() を使用して入力パラメータ $cachePath の意味を記録しています。
2 番目の例では、抑制操作「@」を使用していません。その理由は、これが前の例のように使用され、インクルードされるファイルに実際の致命的なエラーが含まれる場合、致命的なエラーが沈黙するためです。現在、最新の PHP では、これは大きな問題ではありませんが、file_exists() include() の使用は、チェック時間と使用時間の関係で競合状態が発生しますが、安全であり (警告のみ)、非プロシージャにとっては致命的です。存在するファイルのエラーは非表示になりません。さて、プログラミングは難しいので、たとえば、ループでラップして 3 回再試行するとします。
for ループを使用して再試行回数をカウントして保護してみてはいかがでしょうか?
スクリプトに常に 1 つのエグゼキュータしかない場合、この問題は再現できません。
このスクリプトを並行して実行することについて話している場合、問題は、排他モードでファイルを書き込んでも、後の書き込みプロセス中にファイルを読み取ることが保護されないことです。
プロセスはファイルに書き込んでいる (そしてロックを所有している) 可能性がありますが、
require
はロックを尊重しません (ファイルシステムのロックは強制ではなく勧告です)。したがって、正しい解決策は次のとおりです:
リーリー別のプロセスがファイルの上書きを待機している可能性があるため、書き込み後にロックは解放されず、再取得されないことに注意してください。
リリースしないのは、書かれた同じコードも
require
d になるようにするためです。しかし、このこと自体は最初から疑問でした。
後で戻せるようにファイルに書き込む必要があるのはなぜですか?
require
?