This kind of question. There is a base class that is a cache. Now we need to look at the base class before calling child methods and check the feasibility of executing child methods.

interface ICache { public function getCategory(); } abstract class Cache { //Вытягиваем из кэша public function getCategory() { return null; } //Кладём в кэш public function setCategory($data) { } } class FileProvider extends Cache implements ICache { public function getCategory() { $data = parent::getCategory(); if (!is_null($data)) { return $data; } //$data = file_get_content(); parent::setCategory($data); return $data; } } class DBProvider extends Cache implements ICache { public function getCategory() { $data = parent::getCategory(); if (!is_null($data)) { return $data; } //$data = db::query(); parent::setCategory($data); return $data; } } 

And if the presence of methods in child classes is solved using interfaces, then how to make child classes call the parent method before executing? There will be plenty of providers and other people will write them.

Or am I from the wrong side?

    2 answers 2

    Although the solution with the final method is quite working. I would still prefer to do it through composition.

    Plus the composition is that you can combine different ways of caching data with different ways of obtaining data.

    Moreover, it will be possible to cache data in several places at once.

     interface IProvider{ public function getCategory(); } class DBProvider implements IProvider{ public function getCategory(){ //non cached code } } class MemcachedProvider implements IProvider{ private $provider; public function __construct( IProvider $real_provider ){ $this->provider = $real_provider; } public function getCategory(){ // if in cache return result from memcache // in not in cache then use $this->provider and save into cache } } class SessionCachedProvider implements IProvider{ // just example private $provider; public function __construct( IProvider $real_provider ){ $this->provider = $real_provider; } public function getCategory(){ // if value in session then use is // otherwise use $this->provider and save into session } } // обычный provider который ничего не кэшрует $provider = new DBProvider(); // тотже провайдер но эширует в memcached $cached_provider = new MemcachedProvider( $provider ); // провайдер кэширует в сессии $session_cached_provider = new SessionCachedProvider( $provider ); //кэшируем везде где только можно. $super_cache = new SessionCachedProvider( $cached_provider ); 
    • Either I did not fully realize the implementation, or it is not quite that. Providers in my case are third-party APIs, databases and files that need to be parsed. All this with some periodicity. To reduce the load and ping from the API and databases. I decided to cache the received data, and if they are out of date, the provider makes a request and updates it. Services will be complemented by colleagues, so you need to minimize and "secure" the code in them to the maximum. The base methods are closed, and only the methods for getting data remain in the providers. Therefore, most likely I will stop on my own. But thanks for the response - Ninazu

    Is such a solution considered normal?

     abstract class Cache { //Вытягиваем из кэша final public function getCategory() { //Эмуляция получения из кэша $cache = true ? 'cache' : null; if (!is_null($cache)) { return $cache; } $result = $this->loadCategory(); $this->setCategory($result); return $result; } //Кладём в кэш private function setCategory($data) { } abstract protected function loadCategory(); } class FileProvider extends Cache { protected function loadCategory() { return 'query'; } } 
    • one
      The solution will work until Cton wants to overload getCategory. If you didn’t need to “protect” the code from other people, then it’s ok. - Arnial
    • final public function getCategory() and if so? - Ninazu
    • Well, with "no way" I roasted. With final, it really cannot be changed. I believe that this solution is safe. - Arnial