Como ya he comentado en el anterior post sobre las novedades de PHP 5.4, en esta nueva versión se incluyen los traits, que permiten un reuso horizontal de funcionalidades. Aprovechando esta nueva característica, voy a colocar un ejemplo de cómo usar propiedades en una clase y cachear resultados de forma fácil haciendo uso de un trait que he hecho “MagicObjectTrait”.

class TestObject {  
 use MagicObjectTrait;  

 protected $path;  
 public $calledCount = 0;  

 public function __construct($path) {  
  $this->path = $path;  
 }  

 public function __get_cached_files() {  
  $this->calledCount++;  
  return scandir($this->path);  
 }  
}  

$object = new TestObject(__DIR__);  
print_r($object->files);  
print_r($object->files);  
echo "$object\n";  
var_dump($object->calledCount == 1);  

/////////////////////////////////////////  
/////////////////////////////////////////  

trait MagicObjectTrait {  
 /**  
  * Better cache that won't use the object as holder for the cache.  
  *    
  * @var array  
  */  
 static private $__static_cache = array();  

 /**  
  * Returns an ArrayObject unique per object that holds unique  
  * cache information for this object.  
  *   
  * @return ArrayObject  
  */  
 public function getObjectCache() {  
  $cache = &self::$__static_cache[spl_object_hash($this)];  
  if (!isset($cache)) $cache = new ArrayObject();  
  return $cache;  
 }  

 public function __get($name) {  
  $cache = $this->getObjectCache();  
  if (isset($cache[$name])) return $cache[$name];  

  // Calls a getter that will cache the result.  
  if (method_exists($this, $method = "__get_cached_{$name}")) {  
   return $cache[$name] = $v = $this->$method();  
  }  
  // Calls a getter that won't be cached.  
  else if (method_exists($this, $method = "__get_{$name}")) {  
   return $this->$method();  
  }  
  // Calls a function with the same name as the property to get.  
  else if (method_exists($this, $method = "$name")) {  
   return $this->$method();  
  }  
 }  

 public function __isset($name) {  
  $cache = $this->getObjectCache();  
  return (  
   isset($cache[$name]) ||  
   method_exists($this, "__get_{$name}") ||  
   method_exists($this, "__get_cached_{$name}") ||  
   method_exists($this, "{$name}") ||  
   false  
  );  
 }  

 public function __toString() {  
  return sprintf('%s object', get_called_class());  
 }  
}