在HEREDOC字符串中调用PHP函数

时间:2020-03-06 14:27:21  来源:igfitidea点击:

在PHP中,HEREDOC字符串声明对于输出html块确实非常有用。我们可以通过在变量前面加上$来解析变量,但是对于更复杂的语法(例如$ var [2] [3]),则必须将表达式放在{}中。

在PHP 5中,可以在HEREDOC字符串内的{}大括号内实际进行函数调用,但是我们需要做一些工作。函数名称本身必须存储在变量中,并且必须像动态命名函数一样调用它。例如:

$fn = 'testfunction';
function testfunction() { return 'ok'; }
$string = <<< heredoc
plain text and now a function: {$fn()}
heredoc;

如我们所见,这不仅比以下情况更混乱:

$string = <<< heredoc
plain text and now a function: {testfunction()}
heredoc;

除了第一个代码示例外,还有其他方法,例如突破HEREDOC来调用该函数,或者反转问题并执行类似的操作:

?>
<!-- directly output html and only breaking into php for the function -->
plain text and now a function: <?PHP print testfunction(); ?>

后者的缺点是将输出直接放入输出流中(除非我使用输出缓冲),而这可能不是我想要的。

因此,我的问题的实质是:有没有更优雅的方法来解决这个问题?

根据响应进行编辑:当然,某种模板引擎似乎会让我的生活变得更轻松,但是这基本上需要我反转惯用的PHP样式。并不是说那是一件坏事,但这可以解释我的惯性。尽管我想尽办法使生活变得更轻松,所以现在正在研究模板。

解决方案

我将执行以下操作:

$string = <<< heredoc
plain text and now a function: %s
heredoc;
$string = sprintf($string, testfunction());

不知道我们是否认为这会更优雅...

我个人不会使用HEREDOC。它只是不能构成一个好的"模板构建"系统。我们所有的HTML都被锁定在一个字符串中,这有几个缺点

  • 所见即所得没有选择
  • IDE中的HTML没有代码完成
  • 输出(HTML)锁定到逻辑文件
  • 我们最终不得不像现在尝试那样使用hack来实现更复杂的模板,例如循环

获得一个基本的模板引擎,或者仅将PHP与包​​含一起使用,这就是为什么该语言具有&lt;?php?>分隔符的原因。

template_file.php

<html>
<head>
  <title><?php echo $page_title; ?></title>
</head>
<body>
  <?php echo getPageContent(); ?>
</body>

index.php

<?php

$page_title = "This is a simple demo";

function getPageContent() {
    return '<p>Hello World!</p>';
}

include('template_file.php');

我将Smarty作为模板引擎来看一下,我自己还没有尝试过其他模板引擎,但是它做得很好。

如果我们想坚持使用当前的方法而没有模板,那么输出缓冲到底有什么不好呢?它比必须声明变量(要声明的函数的字符串名称)要灵活得多。

我来晚了,但是我随机遇到了它。对于以后的读者,我可能会这样做:

我只会使用输出缓冲区。因此,基本上,我们可以使用ob_start()开始缓冲,然后在其中包含任何函数,变量等的"模板文件",获取缓冲区的内容并将其写入字符串,然后关闭缓冲区。然后,我们使用了所需的任何变量,可以运行任何函数,并且IDE中仍然可以使用HTML语法突出显示。

这就是我的意思:

模板文件:

<?php echo "plain text and now a function: " . testfunction(); ?>

脚本:

<?php
ob_start();
include "template_file.php";
$output_string = ob_get_contents();
ob_end_clean();
echo $output_string;
?>

因此,脚本将template_file.php包含在其缓冲区中,并在运行过程中运行任何函数/方法并分配任何变量。然后,我们只需将缓冲区的内容记录到一个变量中,然后对它进行所需的操作即可。

这样,如果我们不想在当下立即将其回显到页面上,则不必这样做。我们可以循环并继续添加到字符串,然后再输出它。

如果我们不想使用模板引擎,那是最好的方法。

尝试以下操作(作为全局变量,或者在需要时实例化):

<?php
  class Fn {
    public function __call($name, $args) {
      if (function_exists($name)) {
        return call_user_func_array($name, $args);
      }
    }
  }

  $fn = new Fn();
?>

现在,任何函数调用都将通过$ fn实例进行。因此,现有功能testfunction()可以在本地文档中使用{{fn-> testfunction()}

基本上,我们将所有函数包装到一个类实例中,并使用PHP的__call magic方法将类方法映射到需要调用的实际函数。

伙计们应该注意,它也适用于双引号字符串。

http://www.php.net/manual/zh/language.types.string.php

无论如何,有趣的提示。

此代码片段将使用用户范围内定义的函数的名称定义变量,并将其绑定到包含相同名称的字符串。让我示范一下。

function add ($int) { return $int + 1; }
$f=get_defined_functions();foreach($f[user]as$v){$$v=$v;}

$string = <<< heredoc
plain text and now a function: {$add(1)}
heredoc;

现在可以使用了。