📜 ⬆️ ⬇️

Php + Cache + Tags = phpCacheTag

Once, while reading Habr, I stumbled upon the post of a respected dmitrykoterov about cache and tags, which I really sank into the soul. Once, I was messing with the cache, and also, like so many, I came to the conclusion that he (the cache) really lacks native tags, which would be convenient to cut certain portions of the cache with one line. Hack, without going into the naming of variables that are listed under these tags. It is strange that the implementation of this opportunity involved third-party developers, if we talk about the most popular in our memcache.

phpCacheTag As a result, on my next Saturday-Sunday Kodo-Marathon, I decided, nevertheless, to tackle this issue closely and write a universal library for any cache backend, be it memcache or caching in files in pure php. The library was written and settled on googlecode . Sorry for the English, just below I will try to correct.

The goal was to write gracefully and so that it could easily be implemented on any site, no matter how terrible it was written. The Singleton pattern was chosen to implement it, as well as exclusively static calls to public methods. Currently, only memcache is supported, but there is nothing easier to write adapters for other caching systems.

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

in the depths of which thermonuclear reactions take place very complex calculations. Accordingly, it is necessary to cut the cache.

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

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

By the way, if instead of 'GetMeaningOfLife' you 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 we label the current cache item with tags.
CacheTag :: SetTags (CacheTag :: TAG_PURPOSE, CacheTag :: TAG_LIFE);

Tags look like CacheTag :: TAG_YOURTAGNAME, obviously this is just a constant. They need to work hard to announce themselves in the class settings. Here, by the way, I foresee the question “Why are the settings in the classroom? And in general, why separately, the files two times and obchelsya? ". The class is easy to inherit. Tags implemented by the method of constants for convenient autocompletion, array elements would not be that, and indeed in this class all your personal settings are not particularly dependent on the main functionality - for easy and safe updating.

It is very (very) important to note that, in fact, we now have in the cache a variable named purpose, or that you set it to TAG_PURPOSE. In order to fully use the system, we need additional parameters that, in fact, will already identify the values ​​of 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 unit of cache from another (evrkika!). To set a parameter, use the method
CacheTag :: SetParam (CacheTag :: PARAM_PAGE, $ currentPageNum);

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

There are not rare moments when a bulky function returns a result depending on the current user, or, say, a page with a breakdown of long content (read pagination). These variables can, in a sneaky way, be taken implicitly by a function, magically “casting” with the help of global and other tricks. And the parameters, it is very convenient to indicate before starting the generation of the cache, conveniently and accurately.

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

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

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

It became
// $ 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 to comment out the call to the original function and add a couple of lines. Any additional logic and other if / else.
From now on, the data will be collected by themselves, if they are not in the cache, and stored for a certain time in the config file. Otherwise, the result will be returned from the cache.

If you suddenly need to abandon the cache, turn it off in the settings. All calls will be forced through the specified functions. Convulsive find / replace for the entire project is optional.

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

and the meaning of life urgently changed, you progoditsya 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, practice by beginners, and not very often, programmers to output the generated html-content (print / echo / ...) is often how and where it is necessary, instead of returning it and outputting centrally (I personally think that even ob_ * does not justify ). 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 a change in their code, what to do if it’s not scary, you just don’t want to. But, praise phpCacheTag, this problem now does not bother us. In the cache, under the same name both the return value and the content released to the standard stream are stored during the execution of the function / method. This content will be printed out when queried for this variable, as in the actual operation of a function.

Summarizing all the above, we 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 tag constants, 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 full-fledged documentation to the whole matter.

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

Happy coding.

Updated (August 24, 2010):

Version: 0.1.5

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

Source: https://habr.com/ru/post/100726/

All Articles