在Twig中动态使用自定义函数?

时间:2018-03-14 04:36:47

标签: php twig

我有以下用于创建Twig环境对象的类方法。

public function getView($filename, 
                        array $customFunctions = null, 
                        array $customFunctionArgs = null, 
                        $debug = false) {

  $loader = new \Twig_Loader_Filesystem('/App/Views/Templates/Main');
  $twig = new \Twig_Environment($loader);
  if (isset($customFunctions)) {
    foreach ($customFunctions as $customFunction) {
      $customFunction['name'] = new \Twig_SimpleFunction($customFunction['name'], 
      function ($customFunctionArgs) {
        return $customFunction['method']($customFunctionArgs);
      });
      $twig->addFunction($customFunction['name']);
    }
  }
   // Check debugging option
   if ($debug == true && !$twig->isDebug()) {
     $twig->enableDebug();
     $twig->addExtension(new \Twig_Extension_Debug());
   } elseif (!$debug && $twig->isDebug()) {
        $twig->disableDebug();
   }

   $template = $twig->load($filename);

   return $template;
}

问题是,我不明白如何传递值以使其动态工作并将所有对象保留在上下文和范围中。例如,以下是我试图使用它的方法,但我猜不能将变量作为参考传递?

$customFunctions = ['name' => 'customFunctionName', 
                    'method' => $Class->method($arg)];
$customFunctionArgs = [$arg];
$template = $View->getView('template.html.twig', $customFunctions, $customFunctionArgs, true);

我的环境是PHP 5.6&树枝1.35.0。我想这本身不是Twig特定的问题,而是更多关于如何在其他类/方法中使用类对象。

2 个答案:

答案 0 :(得分:0)

构造自定义函数数据数组以及将它们注入模板的循环有一些细微的缺陷。

  • 自定义函数应该是一个三维数组

    $customFunctions = [
        [ // notice the extra level, allowing you to access the name
            'name' => 'customFunctionName',
            'method' => function() { return 'wat'; }
            // you need to pass a callable, not the result of a call
        ]
    ];
    
  • 范围不会像您认为的那样继承,您需要use()您想要访问的变量。我个人不会覆盖这个名字'数组的价值,但这是内部副作用的不可思议的偏执,似乎在实践中有效。

    if (isset($customFunctions)) {
        foreach ($customFunctions as $customFunction) {
            $customFunction['name'] = new \Twig_SimpleFunction(
                $customFunction['name'],
                function () use ($customFunctionArgs, $customFunction) {
                    return $customFunction['method']($customFunctionArgs);
                });
            $twig->addFunction($customFunction['name']);
        }
    }
    
  • 您可能需要在$args上添加循环,以便将正确的参数发送到正确的函数(将$args[0]发送到$customFunctions[0]等。)。

    请注意,这会阻止您将参数发送到自定义函数,除非您在循环中添加它:

    function ($templateArg) use ($customFunctionArgs, $customFunction) {
        return $customFunction['method']($customFunctionArgs, $templateArg);
    }
    

如果您有兴趣,可以使用gist进行测试。

答案 1 :(得分:0)

FélixGagnon-Grenier的回答帮助我找到了解决这个问题的方法。但是,我觉得有必要为需要解决方案的任何人发布所有缺失部分的答案。

我相信如果我从最后开始并在开始时解释它会更有意义。创建阵列时,需要考虑几件事。

  1. 函数所需的任何类对象都必须在带有闭包的use()内声明。
  2. 必须将自定义函数的任何参数声明为闭包的函数参数。这将允许您稍后声明它们。
  3. 我最后添加了一个子数组,其中包含每个自定义函数所需的参数,这样我就不需要单独迭代它们了。

    $customFunctions = [
        [
           'name' => 'customFunction',
           'method' => function($arg1, $arg2) use($Class) { 
                       return $Class->customFunction($arg1, $arg2); 
                                                          },
           'arguments' =>
                 [
                     'arg1', 'arg2'
                 ]
        ]
    ];
    $template = $View->getView(
                               'template.html.twig', 
                                true, 
                                $customFunctions
                              );
    echo $View->renderView($template);
    
  4. 基于此代码(反映上述问题),我不得不做出一些值得注意的修改。

    if (isset($customFunctions)) {
        foreach ($customFunctions as $index => $customFunction) {
            if (isset($customFunctions['arguments'])) {
                $arguments = $customFunctions['arguments'];
            } else {
                $arguments = [];
            }
    
            $twigFunction = new \Twig_SimpleFunction(
                $customFunction['name'], 
                function (...$arguments) use ($customFunction) {
                    return $customFunction['method'](...$arguments);
                });
            $twig->addFunction($twigFunction);
        }
    }
    

    你可以用任何适合你的方式做到这一点,但有一些重要的事情需要考虑我应该努力。再一次,你的参数必须进入函数参数。 function (...$arguments) use ($customFunction)。您的自定义函数将在use()中传递。为了在闭包中实际传递参数,必须使用...来解压缩它们(作为数组)。这适用于PHP 5.6+。它允许将参数动态扩展到正确的数量,否则会出现missing argument错误。