Вызов функций PHP в строках HEREDOC - PullRequest
85 голосов
/ 19 сентября 2008

В 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. Не то чтобы это плохо, но это объясняет мою инерцию ... Я готов выяснить способы облегчения жизни, поэтому сейчас я ищу шаблоны.

Ответы [ 16 ]

60 голосов
/ 23 мая 2012

Если вы действительно хотите это сделать, но немного проще, чем использовать класс, вы можете использовать:

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

$my_string = <<<EOT
Number of seconds since the Unix Epoch: {$fn(time())}
EOT;
52 голосов
/ 19 сентября 2008

Я бы не стал использовать HEREDOC для этого лично. Это просто не подходит для хорошей системы построения шаблонов. Весь ваш HTML заблокирован в строке, которая имеет несколько недостатков

  • Нет опции для WYSIWYG
  • Нет завершения кода для HTML из IDE
  • Вывод (HTML) заблокирован для логических файлов
  • В конечном итоге вам придется использовать хаки, подобные тому, что вы пытаетесь сделать сейчас, для достижения более сложных шаблонов, таких как зацикливание

Получить базовый шаблонизатор или просто использовать PHP с включениями - вот почему язык имеет разделители <?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');
38 голосов
/ 19 сентября 2008

Я бы сделал следующее:

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

Не уверен, если вы считаете это более элегантным ...

17 голосов
/ 22 декабря 2009

Попробуйте это (либо как глобальную переменную, либо создать экземпляр, когда вам это нужно):

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

  $fn = new Fn();
?>

Теперь любой вызов функции проходит через экземпляр $fn. Таким образом, существующая функция testfunction() может быть вызвана в heredoc с {$fn->testfunction()}

По сути, мы упаковываем все функции в экземпляр класса и используем метод PHP __call magic для сопоставления метода класса с фактической функцией, которую необходимо вызвать.

9 голосов
/ 07 сентября 2009

Я немного опоздал, но случайно наткнулся на это. Для будущих читателей вот что я, вероятно, сделаю:

Я бы просто использовал выходной буфер. В общем, вы начинаете буферизацию с помощью ob_start (), затем включаете свой «файл шаблона» с любыми функциями, переменными и т. Д. Внутри него, получаете содержимое буфера и записываете его в строку, а затем закрываете буфер. Затем вы использовали любые переменные, которые вам нужны, вы можете запустить любую функцию, и у вас все еще есть подсветка синтаксиса HTML, доступная в вашей IDE.

Вот что я имею в виду:

Файл шаблона:

<?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 в свой буфер, выполняя любые функции / методы и назначая любые переменные по пути. Затем вы просто записываете содержимое буфера в переменную и делаете с ней все, что хотите.

Таким образом, если вы не хотите отображать его на странице прямо в эту секунду, вам не нужно это делать. Вы можете зацикливаться и продолжать добавлять строку перед ее выводом.

Я думаю, что это лучший способ, если вы не хотите использовать шаблонизатор.

6 голосов
/ 24 марта 2016

Для полноты вы также можете использовать !${''} черная магия взлом парсера :

echo <<<EOT
One month ago was ${!${''} = date('Y-m-d H:i:s', strtotime('-1 month'))}.
EOT;
5 голосов
/ 20 ноября 2014

нашел хорошее решение с функцией обёртывания здесь: 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)}";
5 голосов
/ 17 июня 2011

Я думаю, что использование heredoc отлично подходит для генерации HTML-кода. Например, я нахожу следующее почти полностью нечитабельным.

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

Однако для достижения простоты вы вынуждены оценить функции перед началом работы. Я не верю, что это такое ужасное ограничение, поскольку при этом вы в конечном итоге отделяете свои вычисления от отображения, что обычно является хорошей идеей.

Я думаю, что следующее вполне читабельно:

$page_content = getPageContent();

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

К сожалению, несмотря на то, что вы сделали хорошее предложение связать функцию с переменной, в конце концов, это добавляет некоторый уровень сложности к коду, который не стоит, и делает код менее читабельным , что является основным преимуществом heredoc.

5 голосов
/ 08 декабря 2010

Этот фрагмент будет определять переменные с именами определенных вами функций в области действия пользователя и связывать их со строкой, которая содержит то же имя. Позвольте мне продемонстрировать.

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;

Теперь будет работать.

4 голосов
/ 20 сентября 2008

Я бы посмотрел на Smarty в качестве движка шаблонов - я сам не пробовал никаких других, но он мне помог.

Если вы хотите придерживаться своего текущего подхода без шаблонов, что плохого в буферизации вывода? Это даст вам гораздо больше гибкости, чем объявление переменных, которые являются строковыми именами функций, которые вы хотите вызывать.

...