在 HEREDOC 字符串中调用 PHP 函数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/104516/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 21:27:55  来源:igfitidea点击:

Calling PHP functions within HEREDOC strings

phpstringheredoc

提问by Doug Kavendek

In PHP, the HEREDOC string declarations are really useful for outputting a block of html. You can have it parse in variables just by prefixing them with $, but for more complicated syntax (like $var[2][3]), you have to put your expression inside {} braces.

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

In PHP 5, it ispossible to actually make function calls within {} braces inside a HEREDOC string, but you have to go through a bit of work. The function name itself has to be stored in a variable, and you have to call it like it is a dynamically-named function. For example:

在PHP 5中,这可能实际上使{}一个HEREDOC字符串中括号内的函数调用,但你必须要经过一些工作。函数名本身必须存储在一个变量中,您必须像调用动态命名函数一样调用它。例如:

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

As you can see, this is a bit more messy than just:

正如你所看到的,这不仅仅是:

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

There are other ways besides the first code example, such as breaking out of the HEREDOC to call the function, or reversing the issue and doing something like:

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

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

The latter has the disadvantage that the output is directly put into the output stream (unless I'm using output buffering), which might not be what I want.

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

So, the essence of my question is: is there a more elegant way to approach this?

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

Edit based on responses:It certainly does seem like some kind of template engine would make my life much easier, but it would require me basically invert my usual PHP style. Not that that's a bad thing, but it explains my inertia.. I'm up for figuring out ways to make life easier though, so I'm looking into templates now.

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

采纳答案by Peter Bailey

I would not use HEREDOC at all for this, personally. It just doesn't make for a good "template building" system. All your HTML is locked down in a string which has several disadvantages

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

  • No option for WYSIWYG
  • No code completion for HTML from IDEs
  • Output (HTML) locked to logic files
  • You end up having to use hacks like what you're trying to do now to achieve more complex templating, such as looping
  • 没有 WYSIWYG 选项
  • IDE 中的 HTML 没有代码完成
  • 输出 (HTML) 锁定到逻辑文件
  • 您最终不得不使用像您现在尝试做的那样的技巧来实现更复杂的模板,例如循环

Get a basic template engine, or just use PHP with includes - it's why the language has the <?phpand ?>delimiters.

获取一个基本的模板引擎,或者只使用 PHP 和包含 - 这就是语言具有<?php?>分隔符的原因。

template_file.php

模板文件.php

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

index.php

索引.php

<?php

$page_title = "This is a simple demo";

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

include('template_file.php');

回答by CJ Dennis

If you really want to do this but a bit simpler than using a class you can use:

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

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

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

回答by boxxar

I would do the following:

我会做以下事情:

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

Not sure if you'd consider this to be more elegant ...

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

回答by Isofarro

Try this (either as a global variable, or instantiated when you need it):

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

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

  $fn = new Fn();
?>

Now any function call goes through the $fninstance. So the existing function testfunction()can be called in a heredoc with {$fn->testfunction()}

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

Basically we are wrapping all functions into a class instance, and using PHP's __call magicmethod to map the class method to the actual function needing to be called.

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

回答by BraedenP

I'm a bit late, but I randomly came across it. For any future readers, here's what I would probably do:

我有点晚了,但我偶然遇到了它。对于任何未来的读者,这就是我可能会做的事情:

I would just use an output buffer. So basically, you start the buffering using ob_start(), then include your "template file" with any functions, variables, etc. inside of it, get the contents of the buffer and write them to a string, and then close the buffer. Then you've used any variables you need, you can run any function, and you still have the HTML syntax highlighting available in your IDE.

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

Here's what I mean:

这就是我的意思:

Template File:

模板文件:

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

Script:

脚本:

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

So the script includes the template_file.php into its buffer, running any functions/methods and assigning any variables along the way. Then you simply record the buffer's contents into a variable and do what you want with it.

因此,脚本将 template_file.php 包含到其缓冲区中,运行任何函数/方法并在此过程中分配任何变量。然后您只需将缓冲区的内容记录到一个变量中,然后用它做您想做的事情。

That way if you don't want to echo it onto the page right at that second, you don't have to. You can loop and keep adding to the string before outputting it.

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

I think that's the best way to go if you don't want to use a templating engine.

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

回答by bishop

For completeness, you can also use the !${''}black magicparser hack:

为了完整起见,您还可以使用!${''}黑魔法解析器 hack

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

回答by Michael McMillan

This snippet will define variables with the name of your defined functions within userscope and bind them to a string which contains the same name. Let me demonstrate.

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

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;

Will now work.

现在将工作。

回答by p.voinov

found nice solution with wrapping function here: http://blog.nazdrave.net/?p=626

在这里找到了带有包装功能的不错的解决方案: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)}";

回答by MLU

I think using heredoc is great for generating HTML code. For example, I find the following almost completely unreadable.

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

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

However, in order to achieve the simplicity you are forced to evaluate the functions before you start. I don't believe that is such a terrible constraint, since in so doing, you end up separating your computation from display, which is usually a good idea.

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

I think the following is quite readable:

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

$page_content = getPageContent();

print <<<END
<html>
<head>
  <title>$page_title</title>
</head>
<body>
$page_content
</body>
END;

Unfortunately, even though it was a good suggestion you made in your question to bind the function to a variable, in the end, it adds a level of complexity to the code, which is not worth, and makes the code less readable, which is the major advantage of heredoc.

不幸的是,尽管您在问题中提出了将函数绑定到变量的好建议,但最终它增加了代码的复杂度,这是不值得的,并且使代码的可读性降低,这是Heredoc的主要优势。

回答by nickf

I'd take a look at Smartyas a template engine - I haven't tried any other ones myself, but it has done me well.

我想看看Smarty作为模板引擎 - 我自己没有尝试过其他任何引擎,但它对我来说做得很好。

If you wanted to stick with your current approach sanstemplates, what's so bad about output buffering? It'll give you much more flexibility than having to declare variables which are the the sting names of the functions you want to call.

如果您想坚持使用当前的模板方法,那么输出缓冲有什么不好?与必须声明变量(您要调用的函数的字符串名称)相比,它会给您带来更大的灵活性。