Zend Opcache in PHP improves your page speed by compiling code into machine code and storing the byte code in RAM. With each subsequent hit to a resource code is served from memory rather than being compiled again.
PHP is an interpreted language. What this means is the unlike languages like C / C++, PHP is not compiled once to machine code and then executed from the binary each time.
With PHP, each time a page is viewed on your site the PHP engine parses your source code, compiles the source code to byte code and then executes that byte code.
This is obviously time consuming. To read, parse and compile the same file time and time again seems somewhat insane.
Because reading, parsing and compiling code each time a PHP file is requested is a laborious and time consuming process, there are various opcode caches available. Since PHP 5.5, Zend released their own Zend Opcache as part of the default PHP installation, so that’s the one we use.
When a page is requested the opcode cache is first checked to see if this page’s byte code is in memory and is still valid (fresh). If it is, the byte code is executed directly from memory, which makes it super quick and efficient. The PHP file is not read, parsed or compiled!
Zend Opcache Configuration
As mentioned, since PHP 5.5+ the Zend Opcache is already included in PHP. It is NOT enabled by default, so you’ll need to turn it on and set some parameters in the PHP.ini file.
This is what I use on some of my servers. The exact numbers may differ depending on how much RAM you have, etc, but I use these settings even with as little as 2Gb RAM on servers which are purely nginx web servers with a page cache and cloudflare in front.
; enable the opcache opcache.enable=1; ; set validate_timestamps to 1 to cause PHP to check if the file ; has been modified. ; This check will happen every revalidate_freq seconds. ; If a file is older than revalidate_freq seconds AND it has changed ; it will be removed from the cache and recompiled next time the ; page is accessed. opcache.validate_timestamps=1 opcache.revalidate_freq=600 ; set this to 0 to cause PHP to check the timestamps on each access. ; optionally, you may set opcache.validate_timestamps=0 which ; will mean that PHP will never check for newer versions of your ; cache files. This means if you make code changes you MUST ; restart PHP to see the changes. A pain, but for really busy site ; with few code changes this does improve speed and load. ; How many files can the opcache cache? This should ideally be set ; to a number higher than your actual number of php files. You can ; check that with this command: ; find . -type f -print | grep php | wc -l opcache.max_accelerated_files=7963 ; opcache stores the cache in RAM. This makes it super fast but ; does require a certain amount of memory. Typically on modern ; systems this is not a huge problem. This value is in Mb opcache.memory_consumption=192 ; Interned strings are a PHP optimisation which takes strings in PHP ; which are repeat over and over and places 1 instance in memory ; with a pointer to it. This setting then shares that memory accross ; all your php processes. opcache.interned_strings_buffer=16 ; Causes your destructors to be called faster at the end of a page request ; so that the PHP process is recycled quicker back to the pool of available ; workers opcache.fast_shutdown=1
Difference between opcode caching and page caching
Page is caching is when you cache the output of the page. Opcaching is when you cache the underlying PHP code. Ok, this is probably easier to explain with an example.
Lets assume you have a WordPress site for movie reviews. You’re site’s urls look like this this:
If you have no caching at all (page or opcode) then each time someone visits your page with the “Terminal” review the PHP engine parses the code file, compiles the byte code and then generates the output. This happens EVERY.SINGLE.TIME…
This slow process happens for each page view on any of those pages. So, you decide to install a page cache (I use W3 total cache because it works really nicely with nginx).
Now, when someone visits the “Terminal” page the whole process (read PHP file, parse, compile and generate content) takes place. However, with your page cache, the next time someone visits the “Terminal” page, the page is served from cache, so we save a bunch of steps.
Great, so why do we still need an opcode cache? Because that efficiency is only for the “Terminal” page. If someone now comes along and visits the “The Notebook” page, the whole process is completed for that page.
If they then visit the “Titanic” page, the whole processes is completed for that page.
If you have thousands of pages, with page caches going stale and needing to be recached, we still have a LOT of PHP reading, parsing and compiling code.
With an opcache things are different. The first time someone visits any one of those pages, the PHP code is cached. Now when they visit another page, the page’s output itself still needs to be cached (page cache), but a lot of time is saved because the PHP read, parse, compile steps are already in cache..
So, over your thousands of pages the PHP code is only compiled a single time, then used from memory.
Monitoring Opcode Performance
You may want to see how your opcache is performing. For instance, one of the settings is your memory consumption. Have you allocated enough, or are pages being dropped out of the cache because there’s not enough memory?
Fortunately there are a variety of tools to aid with this. A very nice looking tool can be found on Github: OpCacheGUI
Questions / Comment / Suggestions
I’d love to hear your feedback on opcache performance and settings. Please leave a comment below.