<?php
include_once $_SERVER['DOCUMENT_ROOT'] . '/include/shared-manual.inc';
$TOC = array();
$TOC_DEPRECATED = array();
$PARENTS = array();
include_once dirname(__FILE__) ."/toc/book.opcache.inc";
$setup = array (
  'home' => 
  array (
    0 => 'index.php',
    1 => 'PHP Manual',
  ),
  'head' => 
  array (
    0 => 'UTF-8',
    1 => 'ja',
  ),
  'this' => 
  array (
    0 => 'opcache.preloading.php',
    1 => 'コードの事前ロード',
    2 => 'コードの事前ロード',
  ),
  'up' => 
  array (
    0 => 'book.opcache.php',
    1 => 'OPcache',
  ),
  'prev' => 
  array (
    0 => 'opcache.configuration.php',
    1 => '実行時設定',
  ),
  'next' => 
  array (
    0 => 'ref.opcache.php',
    1 => 'OPcache 関数',
  ),
  'alternatives' => 
  array (
  ),
  'source' => 
  array (
    'lang' => 'ja',
    'path' => 'reference/opcache/preload.xml',
  ),
  'history' => 
  array (
  ),
);
$setup["toc"] = $TOC;
$setup["toc_deprecated"] = $TOC_DEPRECATED;
$setup["parents"] = $PARENTS;
manual_setup($setup);

contributors($setup);

?>
<div id="opcache.preloading" class="chapter">
 <h1 class="title">コードの事前ロード</h1>


 <p class="simpara">
  PHP 7.4.0 以降では、エンジンの起動時に opcache に事前ロードするスクリプトを指定できるようになりました。
  指定されたファイルに存在するあらゆる 関数、クラス、
  インターフェイス や トレイト (定数は除く) は、
  明示的にインクルードすることなく全てのリクエストからグローバルに利用できるようになります。
  これにより(コードが常に利用できるようになるため)、メモリ使用量と、
  パフォーマンスおよび便利さのトレードオフが発生します。
  事前ロードされたスクリプトをクリアするには PHP プロセスの再起動が必要です。
  つまり、この機能は本番環境でのみ役に立ちます。開発環境では役に立ちません。
 </p>

 <p class="simpara">
  パフォーマンスとメモリ使用量の最適なトレードオフは、アプリケーションによって異なることに注意して下さい。
  &quot;全てをあらかじめ読み込む&quot; ことはもっとも簡単な戦略かもしれませんが、
  必ずしも最適とは限りません。
  さらに、コードの事前ロードは、リクエストが終了しても継続して生き残るプロセスの場合にだけ役に立ちます。
  つまり、opcache が有効になった CLI スクリプトは動作はしますが、
  一般的にコードの事前ロードは役に立ちません。
  但し、<a href="ffi.examples-complete.php" class="link">FFI</a> 経由でコードの事前ロードを使う場合は例外です。
 </p>

 <blockquote class="note"><p><strong class="note">注意</strong>: 
  <span class="simpara">
   コードの事前ロードは、Windows ではサポートされていません。
  </span>
 </p></blockquote>

 <p class="simpara">
  コードの事前ロードを設定するには、2つのステップが必要です。
  まず、opcache を有効にしなければなりません。
  その上で、<a href="opcache.configuration.php#ini.opcache.preload" class="link">opcache.preload</a> の値を <var class="filename">php.ini</var> に設定します。
 </p>

 <div class="informalexample">
  <div class="example-contents">
<div class="inicode"><pre class="inicode">opcache.preload=preload.php</pre>
</div>
  </div>

 </div>

 <p class="simpara">
  <var class="filename">preload.php</var> は、サーバーの起動時(PHP-FPM, mod_php, など)
  に一度だけ実行され、リクエストを越えて生き残るメモリ領域に読み込まれる任意のファイルです。
  特権のないシステムユーザに切り替える前に root で起動するサーバーの場合や、
  PHP が root 権限で実行(推奨されません)される場合のために、
  <a href="opcache.configuration.php#ini.opcache.preload-user" class="link">opcache.preload_user</a>
  を使って事前ロードを実行するためのシステムユーザーを指定することが出来ます。
  デフォルトでは、事前ロードを root で行うことは禁止されていますが、
  明示的に <code class="literal">opcache.preload_user=root</code> と指定した場合は許可されます。
 </p>

 <p class="simpara">
  <var class="filename">preload.php</var> スクリプトでは、
  <span class="function"><a href="function.include.php" class="function">include</a></span>,
  <span class="function"><a href="function.include-once.php" class="function">include_once</a></span>, <span class="function"><a href="function.require.php" class="function">require</a></span>, <span class="function"><a href="function.require-once.php" class="function">require_once</a></span>,
  <span class="function"><a href="function.opcache-compile-file.php" class="function">opcache_compile_file()</a></span> で参照されるあらゆるファイルが評価され、
  リクエストを越えて生き残るメモリ領域に読み込まれます。
  次の例では、<var class="filename">src</var> ディレクトリにある全ての
  <var class="filename">.php</var> ファイルが事前ロードされます。
  但し、<code class="literal">Test</code> ファイルの場合を除きます。
 </p>

 <div class="informalexample">
  <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br />$directory </span><span style="color: #007700">= new </span><span style="color: #0000BB">RecursiveDirectoryIterator</span><span style="color: #007700">(</span><span style="color: #0000BB">__DIR__ </span><span style="color: #007700">. </span><span style="color: #DD0000">'/src'</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$fullTree </span><span style="color: #007700">= new </span><span style="color: #0000BB">RecursiveIteratorIterator</span><span style="color: #007700">(</span><span style="color: #0000BB">$directory</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$phpFiles </span><span style="color: #007700">= new </span><span style="color: #0000BB">RegexIterator</span><span style="color: #007700">(</span><span style="color: #0000BB">$fullTree</span><span style="color: #007700">, </span><span style="color: #DD0000">'/.+((?&lt;!Test)+\.php$)/i'</span><span style="color: #007700">, </span><span style="color: #0000BB">RecursiveRegexIterator</span><span style="color: #007700">::</span><span style="color: #0000BB">GET_MATCH</span><span style="color: #007700">);<br /><br />foreach (</span><span style="color: #0000BB">$phpFiles </span><span style="color: #007700">as </span><span style="color: #0000BB">$key </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">$file</span><span style="color: #007700">) {<br />    require_once </span><span style="color: #0000BB">$file</span><span style="color: #007700">[</span><span style="color: #0000BB">0</span><span style="color: #007700">];<br />}<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
  </div>

 </div>

 <p class="para">
  <span class="function"><a href="function.include.php" class="function">include</a></span> と <span class="function"><a href="function.opcache-compile-file.php" class="function">opcache_compile_file()</a></span>
  両方が動作しますが、コードをどう扱うかが異なります。

  <ul class="itemizedlist">
   <li class="listitem"><span class="simpara"><span class="function"><a href="function.include.php" class="function">include</a></span> は、ファイル内でコードを実行しますが、
    <span class="function"><a href="function.opcache-compile-file.php" class="function">opcache_compile_file()</a></span> は実行しません。
    これは、前者のみが条件付きの宣言
    (if ブロック内の関数宣言)をサポートしているということです。</span></li>

   <li class="listitem"><span class="simpara"><span class="function"><a href="function.include.php" class="function">include</a></span> はコードを実行するので、
    ネストして <span class="function"><a href="function.include.php" class="function">include</a></span> されたファイルも評価され、
    それに含まれる宣言も事前ロードされます。</span></li>

   <li class="listitem"><span class="simpara"><span class="function"><a href="function.opcache-compile-file.php" class="function">opcache_compile_file()</a></span>
    は任意の順番でファイルを読み込むことが出来ます。
    つまり、<var class="filename">a.php</var> が クラス <code class="literal">A</code> を定義しており、
    <var class="filename">b.php</var> が <code class="literal">A</code> を継承したクラス
    <code class="literal">B</code> を定義している場合、
    <span class="function"><a href="function.opcache-compile-file.php" class="function">opcache_compile_file()</a></span> はそれらふたつのファイルを任意の順番で読み込めます。
    しかし、<span class="function"><a href="function.include.php" class="function">include</a></span> を使う場合、
    <var class="filename">a.php</var> は <em>必ず</em> 最初にインクルードしなければなりません。
   </span></li>

   <li class="listitem"><span class="simpara">
     どちらの場合も、後に読み込まれるスクリプトが、
     既に事前ロードされているファイルをインクルードしていれば、
     スクリプトの内容は実行されます。しかし、そこで定義されているシンボルは再定義されません。
     <span class="function"><a href="function.include-once.php" class="function">include_once</a></span> を使っても、
     ファイルが二度インクルードされることを妨げません。
     ファイルで定義されたグローバルな定数をインクルードするために、
     ファイルを再読み込みする必要があるかもしれません。
     なぜなら、定数は事前ロードでは処理されないからです。
   </span></li>
  </ul>

  どちらのアプローチが優れているかは、あなたがどのような挙動を望むか次第です。
  オートローディング と一緒に使うことで、
  <span class="function"><a href="function.opcache-compile-file.php" class="function">opcache_compile_file()</a></span> は大きな柔軟性を得られます。
  一方で、手動でコードをロードする場合、
  <span class="function"><a href="function.include.php" class="function">include</a></span> を使うほうが堅牢になるでしょう。
 </p>

</div>
<?php manual_footer($setup); ?>