OPcache Preloading

PHP 7.4.0부터 엔진이 시작될 때 스크립트를 opcache에 미리 로드하도록 PHP를 구성할 수 있습니다. 해당 파일의 모든 함수, 클래스, 인터페이스 또는 특성(상수 제외)은 명시적으로 포함할 필요 없이 모든 요청에 ​​대해 전역적으로 사용할 수 있습니다. 이는 기준 메모리 사용을 위해 편의성과 성능(코드를 항상 사용할 수 있기 때문에)을 절충합니다. 또한 사전 로드된 스크립트를 지우려면 PHP 프로세스를 다시 시작해야 합니다. 즉, 이 기능은 개발 환경이 아닌 프로덕션 환경에서만 실용적으로 사용할 수 있습니다.

성능과 메모리 간의 최적의 균형은 응용 프로그램에 따라 다를 수 있습니다. "모든 것을 미리 로드"하는 것이 가장 쉬운 전략일 수 있지만 반드시 최상의 전략은 아닙니다. 또한 사전 로드는 한 요청에서 다른 요청으로의 지속적인 프로세스가 있는 경우에만 유용합니다. 즉, opcache가 활성화된 경우 CLI 스크립트에서 작동할 수 있지만 일반적으로 무의미합니다. FFI 라이브러리에서 사전 로드를 사용하는 경우는 예외입니다.

메모: Windows에서는 사전 로드가 지원되지 않습니다.

사전 로드 구성에는 두 단계가 포함되며 opcache를 활성화해야 합니다. 먼저 php.ini에서 opcache.preload 값을 설정합니다.

opcache.preload=preload.php

preload.php는 서버 시작(PHP-FPM, mod_php 등) 시 한 번 실행되고 영구 메모리에 코드를 로드하는 임의의 파일입니다. PHP가 루트로 실행되는 경우(권장하지 않음), opcache.preload_user 값은 사전 로드를 실행할 대체 시스템 사용자를 지정할 수 있습니다. 루트로 사전 로드를 실행하는 것은 허용되지 않습니다.

preload.php 스크립트에서 include, include_once, require, require_once 또는 opcache_compile_file()이 참조하는 모든 파일은 영구 메모리로 구문 분석됩니다. 다음 예에서 src 디렉토리의 모든 .php 파일은 테스트 파일이 아닌 한 미리 로드됩니다.

                  
<?php
$directory = new RecursiveDirectoryIterator(__DIR__ . '/src');
$fullTree = new RecursiveIteratorIterator($directory);
$phpFiles = new RegexIterator($fullTree, '/.+((?<!Test)+\.php$)/i', RecursiveRegexIterator::GET_MATCH);

foreach ($phpFiles as $key => $file) {
    require_once($file[0]);
}
?>
                  
                

includeopcache_compile_file() 모두 작동하지만 코드가 처리되는 방식에 대해 다른 의미를 갖습니다.

  • include는 파일의 코드를 실행하지만 opcache_compile_file()은 실행하지 않습니다. 즉, 전자만 조건부 선언(if 블록 내부에 선언된 함수)을 지원합니다.
  • include는 코드를 실행하기 때문에 중첩된 included 파일도 구문 분석되고 해당 선언이 미리 로드됩니다.
  • opcache_compile_file()은 파일을 어떤 순서로든 로드할 수 있습니다. 즉, a.php가 클래스 A를 정의하고 b.php가 A를 확장하는 클래스 B를 정의하면 opcache_compile_file()은 이 두 파일을 임의의 순서로 로드할 수 있습니다. 그러나 include를 사용할 때는 a.php가 먼저 포함되어야 합니다.
  • 두 경우 모두 나중 스크립트에 이미 사전 로드된 파일이 포함되어 있으면 해당 내용은 계속 실행되지만 이 스크립트에서 정의하는 기호는 재정의되지 않습니다. include_once를 사용하면 파일이 두 번째로 포함되는 것을 방지할 수 없습니다. 파일에 정의된 전역 상수를 포함하려면 파일을 다시 로드해야 할 수 있습니다. 이러한 상수는 사전 로드로 처리되지 않기 때문입니다.

따라서 어떤 접근 방식이 더 나은지는 원하는 동작에 따라 다릅니다. 그렇지 않으면 자동 로더를 사용하는 코드를 사용하여 opcache_compile_file()을 사용하면 더 큰 유연성을 얻을 수 있습니다. 그렇지 않으면 수동으로 로드되는 코드를 사용하면 include이 더 강력해집니다.