代码之家  ›  专栏  ›  技术社区  ›  EternalHour

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

  •  0
  • EternalHour  · 技术社区  · 6 年前

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

    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。我想这本身并不是一个特定于细枝的问题,而是关于如何在其他类/方法中使用类对象的更多问题。

    2 回复  |  直到 6 年前
        1
  •  1
  •   EternalHour    6 年前

    Flix Gagnon 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);
      

    基于这段代码(反映了上述问题),我不得不进行一些显著的修改。

    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) 。您的自定义函数将在 使用() 。为了在闭包中实际传递参数,必须使用 ... 将其解包(作为数组)。这适用于PHP 5.6+。它允许将参数动态扩展到正确的数量,否则您将得到 missing argument 错误。

        2
  •  0
  •   Félix Adriyel Gagnon-Grenier    6 年前

    在如何构造自定义函数数据数组以及将其注入模板的循环中,存在一些细微的缺陷。

    • 自定义函数应为三维数组

      $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() 要访问的变量。我个人不会覆盖数组的“name”值,但这是对内部副作用的不可思议的偏执,在实践中似乎是可行的。

      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 如果你感兴趣的话,可以进行测试。