在HEREDOC字符串中调用PHP函数

Dou*_*dek 88 php string heredoc

在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;
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,这比仅仅更麻烦:

$string = <<< heredoc
plain text and now a function: {testfunction()}
heredoc;
Run Code Online (Sandbox Code Playgroud)

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

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

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

所以,我的问题的实质是:有更优雅的方法来解决这个问题吗?

根据回复进行编辑:看起来某种模板引擎看起来确实会让我的生活变得更轻松,但这需要我基本上颠倒我常用的PHP风格.这不是一件坏事,但它解释了我的惯性......我想找出让生活变得更轻松的方法,所以我现在正在研究模板.

CJ *_*nis 66

如果你真的想这样做,但比使用类更简单,你可以使用:

function fn($data) {
  return $data;
}
$fn = 'fn';

$my_string = <<<EOT
Number of seconds since the Unix Epoch: {$fn(time())}
EOT;
Run Code Online (Sandbox Code Playgroud)

  • 一个更紧凑的定义:`$ fn = function fn($ data){return $ data; };` (2认同)

Pet*_*ley 52

亲自,我根本不会使用HEREDOC.它只是没有一个好的"模板构建"系统.您的所有HTML都被锁定在一个字符串中,该字符串有几个缺点

  • WYSIWYG没有选项
  • IDE中的HTML没有代码完成
  • 输出(HTML)锁定到逻辑文件
  • 你最终不得不像你现在想要做的那样使用hack来实现更复杂的模板,比如循环

得到一个基本的模板引擎,或者只是使用PHP与包括-这就是为什么语言具有<?php?>分隔符.

template_file.php

<html>
<head>
  <title><?php echo $page_title; ?></title>
</head>
<body>
  <?php echo getPageContent(); ?>
</body>
Run Code Online (Sandbox Code Playgroud)

的index.php

<?php

$page_title = "This is a simple demo";

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

include('template_file.php');
Run Code Online (Sandbox Code Playgroud)

  • Short更好,更清洁,更容易阅读.在你的观点中`<?= $ title?>`比**更好**?php echo $ title; ?>.不利的是,对于分销来说,很多ini都有短标签.**但猜猜怎么了??从*PHP 5.4*开始,无论ini设置如何,都在PHP中启用了短标签!因此,如果您的编码要求为5.4+(例如,假设您正在使用特征),请继续使用那些非常棒的短标签! (11认同)
  • echo有一个简写:`<?= $ valueToEcho;?>`或`<%= $ valueToEcho;%>`取决于你的INI设置. (8认同)
  • 我读到的关于使用这些短款的大多数内容都说使用它们是一种不好的做法,我同意.所以不幸的是,如果您正在编写用于分发的代码,则不能依赖于这些INI设置,从而使得PHP的"支持"对于分布式代码没有实际意义.FWIW,我不得不多次修复其他人的WordPress插件中的错误,因为他们使用了这些短信. (3认同)
  • 不,我并不是说我必须输入 7 个字符是一种耻辱;你错误地归因于我的问题。我关心的不是*打字*,而是*阅读*。这些字符会产生大量视觉干扰,使扫描源代码和理解代码在做什么变得更加困难。至少对我来说,阅读HEREDOC 是_很多_。_(顺便说一句,它是 7 个字符的时间,它在给定的 HTML 片段中使用了多少次。但我离题了。)_ (2认同)
  • 顺便说一下,即使关闭短标签,默认情况下也会在5.4中启用<?= $ blah?>. (2认同)
  • 问题是关于将函数调用插入到定界符字符串中。这不是关于是否合适的判断。这是对提问者的判断。模板引擎是一个愚蠢的想法,因为 PHP 已经是一种模板语言。 (2认同)

小智 39

我会做以下事情:

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

不确定你是否认为这更优雅......


小智 17

试试这个(作为全局变量,或在需要时实例化):

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

  $fn = new Fn();
?>
Run Code Online (Sandbox Code Playgroud)

现在任何函数调用都通过$fn实例.因此testfunction()可以在heredoc中调用现有函数{$fn->testfunction()}

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

  • 当您不能仅将模板引擎添加到现有项目时,这是一个很好的解决方案.谢谢,我现在正在使用它. (2认同)

Bra*_*enP 9

我有点迟了,但我随机发现了它.对于任何未来的读者,这是我可能会做的:

我只想使用输出缓冲区.基本上,你使用ob_start()启动缓冲,然后在其中包含你的"模板文件",包含任何函数,变量等,获取缓冲区的内容并将它们写入字符串,然后关闭缓冲区.然后,您已经使用了所需的任何变量,可以运行任何函数,并且您仍然可以在IDE中使用HTML语法高亮显示.

这就是我的意思:

模板文件:

<?php echo "plain text and now a function: " . testfunction(); ?>
Run Code Online (Sandbox Code Playgroud)

脚本:

<?php
ob_start();
include "template_file.php";
$output_string = ob_get_contents();
ob_end_clean();
echo $output_string;
?>
Run Code Online (Sandbox Code Playgroud)

因此,脚本将template_file.php包含到其缓冲区中,运行任何函数/方法并在此过程中分配任何变量.然后,您只需将缓冲区的内容记录到变量中,然后使用它执行所需操作.

这样,如果你不想在那一秒就将它回显到页面上,你就不必这样做了.您可以在输出之前循环并继续添加到字符串.

如果您不想使用模板引擎,我认为这是最好的方法.


bis*_*hop 8

为了完整性,您还可以使用!${''} 黑魔法 解析器黑客:

echo <<<EOT
One month ago was ${!${''} = date('Y-m-d H:i:s', strtotime('-1 month'))}.
EOT;
Run Code Online (Sandbox Code Playgroud)

  • 你去过霍格沃茨了吗? (6认同)
  • 这是有效的,因为`false == ''`。定义一个名称长度为 0 (`''`) 的变量。将其设置为您想要的值(`${''} = date('Ymd H:i:s', strtotime('-1 Month'))`)。将其取反 (`!`) 并将其转换为变量 (`${false}`)。`false` 需要转换为字符串,并且 `(string)false === ''`。如果您尝试打印虚假值,则会出错。以下字符串适用于真值和假值,但代价是更加难以阅读: `"${(${''}=date('Ymd H:i:s', strtotime('-1 Month') ))!=${''}}"`。 (3认同)
  • @Starx哇花花公子,你刚刚完成了我的整个一周!:) (2认同)

Mic*_*lan 5

此片段将在userscope中定义具有已定义函数名称的变量,并将它们绑定到包含相同名称的字符串.让我来证明一下.

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;
Run Code Online (Sandbox Code Playgroud)

现在会工作.


MLU*_*MLU 5

我认为使用heredoc非常适合生成HTML代码.例如,我发现以下几乎完全不可读.

<html>
<head>
  <title><?php echo $page_title; ?></title>
</head>
<body>
  <?php echo getPageContent(); ?>
</body>
Run Code Online (Sandbox Code Playgroud)

但是,为了实现简单性,您必须在开始之前评估功能.我不相信这是一个如此可怕的约束,因为这样做,你最终将你的计算与显示分开,这通常是一个好主意.

我认为以下内容非常易读:

$page_content = getPageContent();

print <<<END
<html>
<head>
  <title>$page_title</title>
</head>
<body>
$page_content
</body>
END;
Run Code Online (Sandbox Code Playgroud)

不幸的是,尽管你提出了一个很好的建议,你将函数绑定到一个变量,最后,它增加了代码的复杂程度,这是不值得的,并使代码的可读性降低,这是heredoc的主要优点.

  • 最近的4年证明,它比其他大多数方法都聪明得多。对于认真研究模板的人,在模板中使用合成(构建由较小页面组成的大页面)并使所有控制逻辑保持分离是标准方法:facebook的ReactJS在这方面(与XHP一样)非常出色,XSLT也是如此(我不爱,但是学术上不错。我要写的唯一的风格注释:我总是在变量周围使用{},主要是为了保持可读性并避免以后发生意外。另外,不要忘记对来自用户的任何数据进行htmlspecialchars()。 (2认同)

小智 5

在这里找到了包装功能很好的解决方案:http://blog.nazdrave.net/?p = 626

function heredoc($param) {
    // just return whatever has been passed to us
    return $param;
}

$heredoc = 'heredoc';

$string = <<<HEREDOC
\$heredoc is now a generic function that can be used in all sorts of ways:
Output the result of a function: {$heredoc(date('r'))}
Output the value of a constant: {$heredoc(__FILE__)}
Static methods work just as well: {$heredoc(MyClass::getSomething())}
2 + 2 equals {$heredoc(2+2)}
HEREDOC;

// The same works not only with HEREDOC strings,
// but with double-quoted strings as well:
$string = "{$heredoc(2+2)}";
Run Code Online (Sandbox Code Playgroud)

  • 在此之前 2.5 年,我提出了完全相同的解决方案。/sf/answers/749930891/ (2认同)

小智 5

今天在 php 7.x 上这有点优雅

<?php

$test = function(){
    return 'it works!';
};


echo <<<HEREDOC
this is a test: {$test()}
HEREDOC;
Run Code Online (Sandbox Code Playgroud)