1

I have a base class with many sub-classes, and a generic function to cache the results of a function. In the cache function, how do I figure out what sub-class was called?

class Base {
  public static function getAll() {
    return CacheService::cached(function() {
      // get objects from the database
    });
  }
}

class X extends Base {}
class Y extends Base {}
class Z extends Base {}

class CacheService {
  function cached($callback) {
    list(, $caller) = debug_backtrace();

    // $caller['class'] is always Base!
    // cannot use get_called_class as it returns CacheService!

    // see if function is in cache, otherwise do callback and store results
  }
}

X::getAll();
Z::getAll();
Aistina
  • 12,435
  • 13
  • 69
  • 89

2 Answers2

1

If you're using PHP >= 5.3, you can do this with get_called_class().

Edit: To make it more clear, get_called_class() has to be used in your Base::getAll() method. You, of course, would then have to tell CacheService::cached() what class this reported (adding a method argument would be the most straight-forward way):

class Base {
  public static function getAll() {
    return CacheService::cached(get_called_class(), function() {
      // get objects from the database
    });
  }
}

class X extends Base {}
class Y extends Base {}
class Z extends Base {}

class CacheService {
  function cached($caller, $callback) {
    // $caller is now the child class of Base that was called

    // see if function is in cache, otherwise do callback and store results
  }
}

X::getAll();
Z::getAll();
FtDRbwLXw6
  • 27,774
  • 13
  • 70
  • 107
  • Ergo, it is impossible to do this without passing an additional parameter to CacheService::cached? – Aistina Jun 19 '12 at 17:00
  • @Aistina: No, it's not impossible. But doing it that way is the most maintainable way, short of redesigning whatever it is that you're making so that you don't need to do what you think you need to do. But if you're set on doing it this way, you can override `Base::getAll()` in all your child classes and have them do nothing except call `parent::getAll()`, which will put these methods on the stack, and you can then use `debug_backtrace()` inside `CacheService::cached()` to pop off the last call and get the child class name. I highly advise against this, though, since it's rather silly. – FtDRbwLXw6 Jun 19 '12 at 21:52
  • Alright, thought so. Then I guess I will go with this solution, making the class parameter optional, and fall back to the stacktrace when it's not passed. Thank you for your help. – Aistina Jun 20 '12 at 08:12
0

Try using the magic constant __CLASS__

EDIT: Like this:

class CacheService {
  function cached($class, $callback) {
    // see if function is in cache, otherwise do callback and store results
  }
}


class Base {
  public static function getAll() {
    return CacheService::cached(__CLASS__, function() {
      // get objects from the database
    });
  }
}

FURTHER EDIT: Using get_called_class:

class CacheService {
  function cached($class, $callback) {
    // see if function is in cache, otherwise do callback and store results
  }
}


class Base {
  public static function getAll() {
    return CacheService::cached(get_called_class(), function() {
      // get objects from the database
    });
  }
}
daiscog
  • 11,441
  • 6
  • 50
  • 62