Php + Cache + Tags = phpCacheTag

    Once, reading Habr, I came across a post of respected dmitrykoterov about cache and tags, which sank into my soul. Just then, I was busy with the cache and, like so many, I came to the conclusion that he (the cache) really lacked native tags, which would make it convenient to chop certain portions of the cache with one line. Hack without going into the naming of the variables that are listed under these tags. It is strange that third-party developers are engaged in the implementation of this feature, if we talk about the most popular memcache among us.

    phpCacheTagAs a result, in my next Saturday-Sunday code-marathon, I decided, nevertheless, to tackle this issue closely and write a universal library for any cache backend, be it memcache or file caching in pure php. The library was written and settled on googlecode . Sorry for the English, a little lower I will try to fix it.



    The goal was to write elegantly and so that it could be easily implemented on any site, no matter how badly it was written. The Singleton pattern was chosen for the sake of implantation, as well as exclusively static calls to public methods. Only memcache is currently supported, but there is nothing easier to write adapters for other cache systems.

    Suppose we have a function call
    $ res = GetMeaningOfLife (true, false, 42);

    in the bowels of which thermonuclear reactions take place very complex calculations. Accordingly, you need to cut the cache.

    It all starts with installing a caching system
    CacheTag :: SetBackend (CacheTag :: BACKEND_MEMCACHE);

    Now we will teach the library to extract data
    CacheTag :: SetFunction ('GetMeaningOfLife', true, false, 42);

    By the way, if instead of 'GetMeaningOfLife' write array ($ UniverseObject, 'GetMeaningOfLife') the data will be extracted from the GetMeaningOfLife method of the UniverseObject object.
    The current cache unit is given its name. It is formed from the name of the called function / method, function parameters and additional cache parameters, which are described below.

    Then brand the current cache element with tags
    CacheTag :: SetTags (CacheTag :: TAG_PURPOSE, CacheTag :: TAG_LIFE);

    Tags look like CacheTag :: TAG_YOURTAGNAME, obviously these are just constants. You need to bother to declare them yourself in the settings class. Here, by the way, I foresee the question, “Why the settings in the class? And in general, why separately, did I miscalculate the files once or twice? ” The class is easy to inherit. Tags are implemented using the constant method for convenient auto-completion, array elements would be different, and indeed in this class all your personal settings that are not particularly dependent on the main functionality are for easy and safe updating.

    It is very (very) important to note that, in fact, we now have a variable in the cache with the name purpose, or that there you set it to TAG_PURPOSE. In order to take full advantage of the system, we need additional parameters, which, in fact, will already identify the values ​​of the variables in the cache. Tags simply logically enclose the rest, smaller values ​​in groups, convenient for deletion.

    Like tags, parameters are also constants. And they look like CacheTag :: PAR_YOURPARNAME. They serve in order to distinguish one cache unit from another (eurykika!). To set the parameter, use the method
    СacheTag :: SetParam (CacheTag :: PARAM_PAGE, $ currentPageNum);

    Once again, I note: parameters are not an optional feature. There will be no holiday without them. And the meaning of the tags disappears, since the variable name is not set explicitly, but is assembled from the specified tags and parameters.

    Moments are not uncommon when a bulky function returns a result depending on the current user, or, say, a page broken down by long content (read pagination). These variables can be vilely taken by the function implicitly, magically “casted” using global and other tricks. And it’s very convenient to specify the parameters before starting the cache generation, conveniently and accurately.

    Now you can collect data
    $ res = CacheTag :: Fetch ();

    That's all. What do we have in the end:

    It was
    $ res = GetMeaningOfLife (true, false, 42);

    Has become
    // $ res = GetMeaningOfLife (true, false, 42);
    CacheTag :: SetFunction ('GetMeaningOfLife', true, false, 42);
    CacheTag :: SetTags (CacheTag :: TAG_PURPOSE, CacheTag :: TAG_LIFE);
    CacheTag :: SetParam (CacheTag :: PARAM_PAGE, $ currentPageNum);
    $ res = CacheTag :: Fetch ();

    All we needed to do was comment out the call to the original function and add a couple of lines. No additional logic and other if / else.
    From now on, the data will be taken by itself if it is not in the cache, and stored for a certain time in the config. Otherwise, the result will be returned from the cache.

    If you suddenly need to immediately abandon the cache, turn it off in the settings. All calls will forcefully pass through the specified functions. Fidgety find / replace throughout the project is optional.

    Sooner or later, the moment comes when the cache needs to be updated. Well, for example, if, suddenly, you have
    new BabyBorn ('boy'); *

    and the meaning of life has changed urgently, you will need a method
    CacheTag :: Flush ();

    It is used instead of CacheTag :: Fetch () ;. Those. we set the necessary tags, parameters and variables corresponding to this set will be marked for deletion.
    Everything, the past meaning of life is no longer relevant. At the next appeal, it will be taken again.

    By the way, it is not uncommon for beginners, and not so much, to programmers to output the generated html content (print / echo / ...) as and where it is necessary, instead of returning it and displaying it centrally (I personally think that even ob_ * does not justify this ) Content can be displayed in several places, including functions called from cached. Such projects, at times, are not easy to cache in standard ways, without changing their code, what to do if it’s not scary, then you just don’t want to. But praise to phpCacheTag, this problem does not bother us from now on. In the cache, under the same name, both the return value and the content released into the standard stream during the execution of the function / method are stored. This content will be printed (print) upon request to this variable, as in the real work of the function.

    Summing up all the above, we will put everything together in the simplest example:

    error_reporting (E_ALL);
    require_once ("CacheTag.class.php");

    function f ()
    {
    sleep (1);
    return 2;
    }

    CacheTag :: SetBackend (CacheTag :: BACKEND_MEMCACHE);
    CacheTag :: SetFunction ('f');
    CacheTag :: SetTags (CacheTag :: TAG_PRODUCT);
    CacheTag :: SetParam (CacheTag :: PARAM_ID, 2);
    CacheTag :: SetTimeout (0.1);
    CacheTag :: Fetch ();


    Create constants for tags, parameters and backends in the config class. Their values, by the way, are unimportant, the main thing is that they do not overlap.

    By and large, that's all. I will try to force myself to be a good programmer and write complete documentation for this whole thing.

    In the meantime, you are welcome to try , constructively criticize and report bugs.

    Happy coding.

    Updated (August 24, 2010):



    version: 0.1.5
    • Bug: Settings are not reset after calling Flush ()
    • Bug: No debug message for Replace ()
    • Changed: Changed example.php
    • Changed: Modified Fetch (), so as not to access the cache when it is not necessary
    • Changed: It is possible to use a zero time limit value
    • Changed: Memcache uses 127.0.0.1 instead of localhost




    * The BabyBorn class is not part of the library. If necessary, you can write it yourself.

    Also popular now: