【问题标题】:Calling PHP language constructs using a string使用字符串调用 PHP 语言结构
【发布时间】:2011-04-08 15:54:15
【问题描述】:

我想缓冲一些内容。获取内容的方式取决于,这就是为什么我在缓冲区函数中添加了一个类型参数来定义是包含还是回显源。

PHP

<?php

function bufferContent($source, $type = 'include') {
  ob_start();
  $type($source);
  return ob_get_clean();
}

echo bufferContent('<html>test</html>', 'echo');

?>

输出

Fatal error: Call to undefined function echo() in #### on line 5

这是为什么呢?难道不能通过字符串变量调用标准的PHP函数,如echo()或include()吗?

编辑:稍微改变了问题,使其更适合答案。

【问题讨论】:

  • 您可以做的最接近的事情是将您的echo 替换为print_r.. 它不一样(print_r 不仅打印字符串)但是......它会起作用。 (print 也是一种语言结构)

标签: php buffer call language-construct


【解决方案1】:

echo 不是函数:它是一种语言结构——因此不能这样调用。

您可能会定义一个函数,该函数本身会调用 echo - 并在调用 bufferContent 时使用您的函数:

function my_echo($str) {
    echo $str;
}
echo bufferContent('<html>test</html>', 'my_echo');


一个参考,引用the manual page of echo:

注意:因为这是一个语言结构而不是一个函数,它 无法使用variable functions调用

【讨论】:

    【解决方案2】:

    您不能从字符串变量中调用 echo、include、require_once、isset、empty,因为它们的行为不像普通函数。 你可以使用

    include "file.php";
    

    与

    include("file.php");
    

    您可以创建一个包装函数,然后像这样调用它们:

    function wrap_echo($str) { echo($str); };
    

    然后做

    $f = "wrap_echo";
    $f("sth");
    

    【讨论】:

      【解决方案3】:

      会因此受到责骂,但在您的情况下,懒惰的解决方法是:

      eval(" $type(\$source); ");
      

      这适用于普通函数和语言结构。尽管您确实应该在特殊情况下使用开关,并为其他所有情况保留正常的变量函数调用。

      【讨论】:

      • +1 最好是function a($f) { if (in_array($f, array('echo', 'print', 'include', 'include_once', 'require', 'require_once'))) { eval($type . '($source)'); } else { $type($source); } },以便仅评估某些“功能”,因此不会引入潜在的安全漏洞。
      • 非常感谢,各位。我现在使用eval("$type('$source');");,而之前检查$type:if (!in_array($type, array('include', 'echo', 'print'))) die('error message');
      【解决方案4】:
      function buffer_content($source, $type = 'echo') {
          if(!is_string($type)){
              trigger_error('$type must be a string.', E_USER_WARNING);
              return false;
          }
          if(is_object($source) and method_exists($source, '__toString')){
              $source = strval($source);
          }elseif(is_scalar($source)){
              $source = strval($source);
          }elseif(!is_string($source)){
              trigger_error('$source must be a string as non-scalars do not echo nicely.', E_USER_WARNING);
              return false;
          }
          ob_start();
          switch(strtolower($type)){
              case 'include': include $source; break;
              case 'include_once': include_once $source; break;
              case 'require': require $source; break;
              case 'require_once': require_once $source; break;
              case 'echo': echo $source; break;
              default: trigger_error("\$type '{$type}' is not supported.", E_USER_WARNING); break;
          }
          return ob_get_clean();
      }
      

      ^ 你需要即兴发挥一点。这就是你做你需要做的事情的方式!但是有更好、更有效/更通用的方法来做到这一点。

      【讨论】:

      • 为什么不在之后使用$valid_types = array("include", "include_once", "require", "require_once"); ... in_array($type, $valid_types, true)... 和switch/case 之类的东西,这可能使它比所有elseif(!strcasecmp()) 更具可读性
      • @phant0m 人们倾向于在switch case break 上窒息,而不是在ifs 上。如果您忘记了break;,那么您就有问题了。使用if,所有内容都很好,对初学者很友好。每个人都明白 if :) 和 {...} 很好地分隔块。
      • 我不认为初学者友好是一个有效的论点。在这种情况下,您可以提出相同的论点来放弃类、引用、ob_、闭包等;) "But there are better and more efficient/versatile ways to do it." 例如? :) *P.S. 你不需要“P.S.”注意
      • @phant0m 已更改。 我觉得被跟踪了。 我是否正在接受某种SO 审查:)
      • 嘿,不,我只是注意到你是新来的有前途的帖子;)最后一个小吹毛求疵:你不一定需要在 $source 上进行类型检查,因为 echo 还可以打印其他内容,并且长度/修剪检查也是多余的。
      【解决方案5】:

      您不能将echo 作为函数调用,因为它实际上不是函数,而是 PHP 中的一种语言结构。

      为了有效地调用echo,你可以创建一个包装方法,例如:

      function call_echo($str){
        echo $str;
      }
      

      关于通过字符串调用函数的话题,我会使用call_user_func

      mixed call_user_func ( callback $function [, mixed $parameter [, mixed $... ]] )
      

      所以在你的情况下它会是

      call_user_func($type, $source);
      

      我会选择call_user_func 而不是变量函数,因为它更具可读性且不易混淆。如果我正在阅读您的代码,如果您致电call_user_func,我会立即看到您在做什么

      【讨论】:

        猜你喜欢
        • 2021-07-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-25
        • 1970-01-01
        • 2021-01-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多