We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Volt: access to object property using variable

Is it possible to access object property using variable as the property name?

$obj = new sdClass;
$obj->attr = 'some value';

$key = 'attr';

echo $obj->$key; // some value

In Volt I can't use

{{ obj[key] }}
{{ obj.key }}
edited Apr '14

This is the only result that comes up when searching for this topic, so I thought I'd share my solution.

You are able to embed php code inside Volt templates, so simply adding

<?php echo $obj->$key ?>

inside the Volt template will work.

Edit

Reading through the API, I just found readAttribute() so you can also do this:

{{ obj.readAttribute(key) }}


8.1k
edited Apr '14

Cool thing you're reporting back your findings.

I reckon the <?php way is a bit more efficient? (Writing it as <?= $obj->key ?> makes it less verbose, and somewhat prettier IMO btw ;-))

I'm quite pleased it's no hassle to use some direct PHP in your Volt templates, and working directly with the template vars. Saved me already!

(The only dangerous part might be that due to possible changes to Volt in future versions, stuff that's currently working might break?)

Another solution to the question asked could be to implement PHP's ArrayAcces interface, or using the ArrayObject class.

The <?php way probably is a bit more efficient, but by nanoseconds so I wouldn't even bother worrying about efficiency. I personally would prefer the {{ ... }} way, because it reduces the temptation of puting too much logic in the templates.



309

If you want the same speed as PHP, you can add a filter/function in Volt, so that the template is compiled as PHP.

For example:

$volt->getCompiler()->addFilter('getAttribute', function ($resolvedArgs, $exprArgs) use ($di)
{
    return vsprintf('%s->{%s}', explode(', ', $resolvedArgs));
});

I'm not sure it would work in all case, but:

    {{ obj|getAttribute(key) }}

will compile as:

    <?php echo $obj->{$key}; ?>

Thanks for this solution Yvan, I have an application that uses a lot of variables and any speed improvement matters. In which file do you add your function?

If you want the same speed as PHP, you can add a filter/function in Volt, so that the template is compiled as PHP.

For example:

$volt->getCompiler()->addFilter('getAttribute', function ($resolvedArgs, $exprArgs) use ($di)
{
   return vsprintf('%s->{%s}', explode(', ', $resolvedArgs));
});

I'm not sure it would work in all case, but:

   {{ obj|getAttribute(key) }}

will compile as:

   <?php echo $obj->{$key}; ?>


309
edited Aug '16

@8webdesign: you just have to add it where you declared your volt engine, in your DI initialisation. You should have some lines like:

$view->registerEngines([
    '.volt' => function ($view, $di)
    {
        $volt = new Volt($view, $di);
        // Add it here:
        $volt->getCompiler()->addFilter('getAttribute', function ($resolvedArgs, $exprArgs) use ($di)
        {
            return vsprintf('%s->{%s}', explode(', ', $resolvedArgs));
        });
        return $volt;
    }
]);