added support for __call() in expression resolution (closes #2)

The new algorithm for object method resolution is now the following:

  * get all methods declared for `$object` using ReflectionObject::getMethods()
  * check if `$item` is in the list of method names
  * check if `get$item` is in the list of method names
  * check if `__call` is defined and pass `$item` as the method name
This commit is contained in:
Fabien Potencier
2010-05-10 12:46:52 +02:00
parent 362613c302
commit 79e5058611
3 changed files with 59 additions and 9 deletions
+2
View File
@@ -1,5 +1,7 @@
* 0.9.6-DEV
* added support for __call() in expression resolution
* fixed node visiting for macros (macros are now visited by visitors as any other node)
* fixed nested block definitions with a parent call (rarely useful but nonetheless supported now)
* added the cycle filter
* fixed the Lexer when mbstring.func_overload is used with an mbstring.internal_encoding different from ASCII
+30 -9
View File
@@ -11,10 +11,12 @@
abstract class Twig_Resource
{
protected $env;
protected $cache;
public function __construct(Twig_Environment $env)
{
$this->env = $env;
$this->cache = array();
}
public function getEnvironment()
@@ -36,12 +38,12 @@ abstract class Twig_Resource
return $object[$item];
}
if ($arrayOnly)
if ($arrayOnly || !is_object($object))
{
return null;
}
if (is_object($object) && isset($object->$item))
if (isset($object->$item))
{
if ($this->env->hasExtension('sandbox'))
{
@@ -51,13 +53,32 @@ abstract class Twig_Resource
return $object->$item;
}
if (
!is_object($object) ||
(
!method_exists($object, $method = $item) &&
!method_exists($object, $method = 'get'.$item)
)
)
$class = get_class($object);
if (!isset($this->cache[$class]))
{
$r = new ReflectionClass($class);
$this->cache[$class] = array();
foreach ($r->getMethods(ReflectionMethod::IS_STATIC | ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_FINAL) as $method)
{
$this->cache[$class][strtolower($method->getName())] = true;
}
}
$item = strtolower($item);
if (isset($this->cache[$class][$item]))
{
$method = $item;
}
elseif (isset($this->cache[$class]['get'.$item]))
{
$method = 'get'.$item;
}
elseif (isset($this->cache[$class]['__call']))
{
$method = $item;
}
else
{
return null;
}
+27
View File
@@ -0,0 +1,27 @@
--TEST--
Twig supports __call() for attributes
--TEMPLATE--
{{ foo.foo }}
{{ foo.bar }}
--DATA--
class TestClassForMagicCallAttributes
{
public function getBar()
{
return 'bar_from_getbar';
}
public function __call($method, $arguments)
{
if ('foo' === $method)
{
return 'foo_from_call';
}
return false;
}
}
return array('foo' => new TestClassForMagicCallAttributes())
--EXPECT--
foo_from_call
bar_from_getbar