Twig
Twig copied to clipboard
Support ArrayAccess Context
The Problem
I would like to create a Twig implementation of my templating interop standard, TemplateInterface. One of the types that it allows for context is ArrayAccess, or even more importantly ContainerInterface. This made sense because:
- The context is immutable. You're never going to need to modify it in the template.
- ISP. Depending on
arraymeans depending on something that is necessarily writable, which it doesn't have to be. - Likewise, there is no need to require that all of the values already exist inside the context when rendering.
Decorating a templating engine sounds like a trivial thing, with only a few thin wrappers. Alas, with Twig it is currently also impossible in this case, because although it appears possible to pass ArrayObject as one of the context values, it isn't possible to pass ArrayObject as the context itself: multiple typehints in the call chain, as well as the "merging of global context" prevent that.
Suggested Solution
Would it be possible to add support for the ArrayObject type in context? It would define more narrowly, and therefore more precisely, what the context needs to be - see the points above. That would allow Twig implementations of any template standard that only depends on getting and checking for values in the context.
One way to do that would be by type-hinting ArrayAccess. This has the disadvantage of requiring wrappers, making calls slightly more complex, e.g. $template->render(new ArrayObject([/* ... */])).
Another way is to remove the typehint completely, and implement a userland check instead, e.g. for is_array($context) || $context instanceof ArrayAccess. The disadvantage here is loss of native type-safety. Most of this can probably be mitigated by using PHPDoc or even Psalm. This doesn't break BC.
Of course, a solution could also be to simply use union types, and typehint array|ArrayAccess. But this has the disadvantage of requiring PHP 8.