Cachiranje + eval() ?

Zanima me ali bi se dalo nekaj takega:
primer:

npr. pri izpisu kategorije novic se izvrši kar nekaj stvari.

$category = new NewsCategory($_GET['id']);
$most_viewed = $category->getMostViewed();
$best_rated = $category->getBestRated();

itd...

Jaz bi rad po nekem ključu, npr. po serialize($_GET) pocachiral vrednosti teh spremenljivk.

Ideja je, da bi jih klical nekako takole

$category = CMSCache::handle("new NewsCategory(".$_GET['id'].");");
$most_viewed = CMSCache::handle('$category->getMostViewed();');
$best_rated = CMSCache::handle('$category->getBestRated();');

v CMSCache::handle() bi preverjal:
- če cache že obstaja, bi zapisal vrednost iz cacha v spremenljivko
- v nasprotnem primeri bi pa zagnal komando in zapisal sveži cache

Malo sem se že igral z eval() funkcijo, vendar neuspešno
Ali se to sploh da? Sem brcnil v temo? :)

HELP

5 odgovorov

Hm, zakaj pa ne bi cache-iral outputa? Oz. to je pomojem pravi način, torej cache-iraš output.

Če pa že hoče cache-irati podatke, pa je dobra zadeva kakšen memcache.

Pa še ena ideja, uporabiš ne-ralacijsko bazo, za takšne agregirane podatke. Poglej si Cassandra , tukaj pa je primer, kjer Digg uporablja Cassandro: http://about.digg.com/blog/looking-future-cassandra .

1

verjetno bi se dalo kaj sčarati v tem stilu, vendar toplo odsvetujem, ker je eval nevaren in počasen in koda v stringu je izven dosega parserja (IDE ne razume in napake se odkrijejo šele pri evalu). Ta pristop po moje ni v redu.

Poleg tega imaš še varnostno luknjo. Kaj če ti kdo poda parameter id=); zlobna_koda(? :)

Keširaj ali posamezne končne HTML kose, ali pa objekte/arraye in uporabi wrapper za cache:

class NewsCategoryCacher {
  function get($id) {
    if (news $id is in cache)
      return from cache
    else
      $nc = new NewsCategory($id);
      write to cache
  }

  function getMostViewedByCategory($category) {
    if (most viewed $category->id is in cache)
      return from cache
    else
      $most_viewed = $category->getMostViewed();
      write to cache and return
  }
}

in potem uporabljaš:

$category = NewsCategoryCacher::get(234);
$most_viewed = NewsCategoryCacher::getMostViewed($category);

To je osnovna ideja, da se jo precej raztegniti.

BTW, če te zanima framework za večplastno keširanje v PHPju, si oglej LayerCache. Omogoča zelo elegantno večplastno keširanje z zelo malo kode. Na enem projektu recimo uporabljam 3-plastno: izvor je mysql tabela, cachi pa so memcache, apc in še lokalen PHP array.

3

fatg: LayerCache zgleda zelo obetavno. Sem downloadal in bom naštudiral!
Hvala!

@cyber: Zakaj tocno bi bilo tu potrebno uporabljati nerelacijsko bazo? Ob pravilni uporabi relacijske baze ta brez problema zadosca do nekaj milijonov recordov. No ja, zanima me, ce imas morda prakticne izkusnje s Cassandro, ker imam nekaj vprasanj :)

Glede cacha pa raje ustvarite generik, kakor da delate cache objekt za vsak objekt posebej. Npr. LayerCache pocne natanko to. Morda bi bil zaradi dokumentacije tu se primernejsi Zend_Cache (in zaradi moznosti uporabe drugih komponent frameworka).

Se en cisto poenostavljen primer:

// $cache je ze inicializiran
      $id = 'cache_id';
      if (!($data = $cache->load($id))) {
          // zadeva se ni shranjena
          $data = '';
          for ($i = 0; $i < 10000; $i++) {
              $data = $data . $i;
          }
      // shranimo v cache
          $cache->save($data);
      }
      echo $data;

Vec na: http://framework.zend.com/manual/en/zend.cache.html