trait CachableTrait 
{
   protected $instance = null;

   public function __construct() {

      $reflectionClass = new ReflectionClass(
         $this->cachedClassName
      );

      $this->instance = $reflectionClass->newInstanceArgs(
         func_get_args()
      );
   }

   public function __call($name, $arguments) {
      // method exists
      if (method_exists($this->instance, $name)) {

         // should the method be cached
         if (array_key_exists(
                $name, $this->cachedMethods
            )) {

            // key for cache is method name append by hash
            // of arguments
            $key = $this->cachedClassName . '-' . $name
               . '-'
               . hash('sha256', implode('', $arguments));

            // does the cache have the value for the key?
            if (Cache::has($key)) {

               // get the data from the cache
               return Cache::get($key);
            } 
            
            // value not in cache
            // get the value to store by executing
            // the function
            $value = call_user_func_array(array(
               $this->instance,
               $name
            ), $arguments);

            // store key-value in cache
            Cache::add(
               $key,
               $value,
               $this->cachedMethods[$name]
            );

            // return value
            return $value;

         // method should not be cached
         } else {

            return call_user_func_array(
               array($this->instance, $name),
               $arguments
            );
         }

      // method does NOT exist -> throw exception
      } else {
         throw new Exception("Method not found: $name");
      }
   }
}