Fast caching across requests in PHP & .NET

In this article, we’d like to describe something you can benefit from implicitly when using Peachpie compiler. Peachpie compiles PHP sources to regular .NET binaries, which gives us several features that are simply not available to regular PHP. An example of this is caching some data you don’t want to create with every single request over and over.

What we are used to

It is a very common task. You would like to remember some costly created value across all your requests. For example, why would you parse a complex XML file every time? The best practice is to use a memcached extension or APC or to serialize your data into a cache file.

Here we have a simple example:


if (!isset($data)) {
  $data = unserialize( file_get_contents('cached.bin') ); // try to restore data from cache
  if (!isset($data)) {
    $data = [1,2,3]; // imagine something costly in here
    file_put_contents( 'cached.bin', serialize($data) ); // cache the data
  }
}

This is of course highly simplified, but you get the idea. The PHP request lives in a single process and when it ends, all your local and static variables are dismissed. Even though the serialization in PHP is fast and IO operations are cached by the OS, the program still has to do something. In any case, it is usually significantly faster than creating your costly $data from scratch.

.NET and Peachpie

When running applications under .NET, you can benefit from the fact that all the requests run within the same process as threads. Therefore, .NET static fields live across requests and across threads. Actually, in order to simulate PHP static fields in .NET, Peachpie compiler has to generate some magic around them so that their value can be bound to a single request only. But we have also taught it to create real static.

Peachpie static fields

Peachpie compiles PHP code into an equivalent .NET dll. When it has to compile a PHP static field such as this:

class X {
  static $field;
}

it has to wrap it into another class, whose instance is maintained within the current request and then dismissed. Something equivalent to this piece of C#:

public class X {
  public sealed class _statics {
    public PhpValue field = PhpValue.Null;
  }
}

The _statics generated class is maintained by the runtime, instantiated when needed and disposed of by the garbage collector when the request ends. It contains the PHP static field, which is accessed in the PHP code as a regular static field as X::$field.

@appstatic

In Peachpie we are introducing a backward compatible simple addition to this behavior. The compiler understands PHPDoc notation and PHPDoc tags. Static fields annotated with the PHPDoc tag @appstatic become real .NET static fields. As a result, PHP code such as this:

class X {
  /** @appstatic */
  static $field;
}

results in code equivalent to the following C# snippet:

public class X {
  public static PhpValue field = PhpValue.Null;
}

Can you spot the difference? The field becomes static across all threads, i.e. all requests. Not only is it faster and more memory efficient, but it also allows programs to retain individual data for the entire request until the server process gets killed or restarted.

Caching with @appstatic

When a PHP static field is annotated with the @appstatic PHPDoc tag, the field becomes a real .NET static. Be careful not to use it for resources or sensitive class instances; however, when used for arrays or long strings, the benefits are the following:

  • The value is maintained in memory just once, not allocated for every single request.
  • Data is cached in-memory, no serialization is needed.
  • The cache is cleared when the server process is restarted, no time-stamping is needed.
  • The mechanism is backward compatible; the code will still run under regular PHP.
  • The code is more readable.
  • It is easy and declarative to enable caching for a static field.

We hope you liked the two latest articles both dealing with optimizations and performance tuning of PHP applications made possible by Peachpie compiler. If you have any questions, comments or suggestions let us know in the comments section below or on Twitter, Facebook or Gitter and if you haven’t already, make sure you follow us on GitHub.

Share this article:Share on FacebookShare on VKPin on PinterestShare on Google+Tweet about this on TwitterShare on LinkedInShare on Reddit
Posted on November 7, 2017, in category Information, Tutorial, tags: , , , , , , ,