Вызов функций PHP в строках 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;

Как видите, это немного сложнее, чем просто:

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

Это не совсем ответ на ваш вопрос, но, учитывая плохую поддержку вызовов функций в операторах heredoc, я обычно просто генерирую строки, которые мне понадобятся, перед печатью heredoc. Затем я могу просто использовать что-то вроде Text {$string1} Text {$string2} Text в heredoc.

rinogo 06.03.2018 03:21
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
94
1
78 229
17
Перейти к ответу Данный вопрос помечен как решенный

Ответы 17

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

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

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

Ответ принят как подходящий

Лично я бы вообще не использовал 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');

К сожалению, метод встраивания содержимого в PHP делает итоговый HTML-код очень трудным для чтения. Жаль, что PHP не стандартизировал короткие разделители и не предоставил сокращение для эха, как старый ASP (это одна из немногих вещей, которые ASP удалось сделать лучше, чем PHP IMO.)

MikeSchinkel 05.09.2012 00:39

Существует сокращение для echo: <?=$valueToEcho;?> или <%=$valueToEcho;%> в зависимости от ваших настроек INI.

Peter Bailey 05.09.2012 23:26

Практически все, что я читал об использовании этих сокращений, говорит, что их использование - плохая практика, и я согласен. Так, к сожалению, если вы пишете код для распространения не может зависеть от этих параметров INI таким образом делая «поддержку» РНР для них тоо для распределенного кода. FWIW, мне приходилось исправлять ошибки в плагинах WordPress других людей не раз, потому что они использовали эти сокращения.

MikeSchinkel 06.09.2012 01:27

Я согласен, но это странная вещь, на которую можно «жаловаться». Вы в основном говорите: «Жалко, что мне приходится набирать 7 дополнительных символов».

Peter Bailey 06.09.2012 22:32

Нет, я не говорю, что жаль, что мне приходится набирать 7 символов; вы неправильно приписываете мои проблемы. Меня беспокоит не набор текста, а чтение. Эти символы создают много визуального шума, что значительно затрудняет сканирование исходного кода и понимание того, что он делает. По крайней мере, для меня МНОГО легче читать HEREDOC. (И, кстати, это 7 символов, сколько бы раз оно ни использовалось в данном фрагменте HTML. Но я отвлекся.)

MikeSchinkel 10.09.2012 01:32

Краткое содержание приятнее, чище и легче для чтения. По вашему мнению, <?=$title?>много лучше, чем <? Php echo $ title; ?>. Обратной стороной является то, что для распространения многие ini имеют короткие теги. Но, угадайте что ?? Начиная с PHP 5.4, короткие теги включены в PHP независимо от настроек ini! Так что, если вы кодируете с требованием 5.4+ (допустим, вы используете черты характера, например), продолжайте и используйте эти замечательные короткие теги !!

Jimbo 14.03.2013 13:57

Что такого сложного во встраивании PHP в HTML с правильными разделителями <? Php?>? На читабельность это не влияет. На самом деле, я думаю, что большинство разработчиков, которым не нравится удобочитаемость, пишут плохо сформированный HTML - больше, чем PHP. Просто помните: одна из P в PHP означает «препроцессор». Используйте PHP из-за его сильных сторон и, прежде всего, будьте проще!

FredTheWebGuy 24.07.2013 05:59

Кстати, <? = $ Blah?> Включен в 5.4 по умолчанию, даже если короткие теги отключены.

callmetwan 16.05.2014 20:15

Получается, что короткий ответ - «Нет». Вы действительно не можете вызвать функцию непосредственно из строки HEREDOC. Мне потребовалось время, чтобы понять это!

Ifedi Okonkwo 21.08.2014 19:37

@IfediOkonkwo На самом деле, вы можете, и здесь есть несколько ответов, которые показывают, как это сделать. Это просто не считается хорошей практикой.

CJ Dennis 21.12.2014 09:27

Я не мог не согласиться с тем, что хочу сделать таким образом «более сложные шаблоны, такие как циклы». Внедрение потока управления в шаблон HTML - это первый шаг к экспоненциальному увеличению сложности. Имеет смысл сначала организовать выходные данные в соответствующих структурах данных, а затем использовать функции вашей коллекции для сопоставления / уменьшения их. Он отлично работает в ReactJS. Вам никогда не понадобится специальный микроязык для создания циклов.

Josh from Qaribou 14.09.2015 21:28

Речь идет о вставке вызовов функций в строки heredoc. Дело не в суждении о том, уместно это или нет. Это суждение для человека, задавшего вопрос. Механизмы создания шаблонов - глупая идея, потому что PHP уже является языком шаблонов.

JG Estiot 26.02.2018 04:48

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

xorinzor 19.09.2020 17:29

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

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

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

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

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

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

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

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

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

Brandon 03.02.2011 22:40

не следует широко использовать, когда производительность критична: я несколько раз читал, что производительность call_user_func_array хуже, последний раз в комментариях на php.net: php.net/manual/en/function.call-user-func-array.php#97473

Markus 18.10.2011 20:43

Отлично! Мне это нравится, почему я не подумал об этом?!? :-)

MikeSchinkel 05.09.2012 00:37

Ребята, обратите внимание, что он также работает со строками в двойных кавычках.

http://www.php.net/manual/en/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;

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

@MichaelMcMillian лучше не иметь переменных с такими же именами, как у любой функции, верно?

s3c 29.02.2020 19:36

Немного поздно, но все же. Это возможно в heredoc!

Загляните в руководство по php, раздел «Сложный (фигурный) синтаксис»

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

Doug Kavendek 13.04.2011 20:09

Я думаю, что использование 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.

Последние 4 года доказали, что это намного умнее, чем большинство других подходов. Использование композиции в ваших шаблонах (создание большой страницы, состоящей из меньших страниц) и разделение всей логики управления - стандартный подход для всех, кто серьезно относится к шаблонам: ReactJS facebook отлично подходит для этого (как и XHP), как и XSLT (который Не люблю, но академически здоров). Единственные стилистические замечания, которые я сделаю: я всегда использую {} вокруг своих варов, в основном для единообразия в удобочитаемости и во избежание случайностей в дальнейшем. Также не забывайте использовать htmlspecialchars () для любых данных, поступающих от пользователей.

Josh from Qaribou 14.09.2015 21:20

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

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

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

Отлично @CJDennis! Это лучшее и самое чистое решение для использования вызова функций внутри HEREDOC. В некоторых ситуациях есть хороший ресурс. На своем сайте я использую HEREDOC для создания форм с 22 строками наборов полей (блок HEREDOC внутри цикла FOR) с вызовом функции для генерации позиции tabindex.

Paulo Buchsbaum 18.01.2013 08:12

Вы даже можете сделать это: $my_string = "Half the number of seconds since the Unix Epoch: {$fn(time() / 2 . ' Yes! Really!')}";

CJ Dennis 29.11.2013 08:33

более компактное определение: $fn = function fn($data) { return $data; };

devsmt 19.09.2016 16:16

@devsmt Вы правы. И даже короче: $fn = function ($data) { return $data; };

CJ Dennis 20.09.2016 05:31

о, годегольф? хорошо, впустите меня: $fn=function($data){return $data;}; должен быть самым коротким

My1 26.12.2016 01:42

@ My1 Нет, $f=function($d){return$d;}; короче, но это не Code Golf.

CJ Dennis 27.12.2016 10:08

Я даже не знал, что ты можешь вернуться без места

My1 27.12.2016 19:57

@ My1 Гольф? $fn='strval';

Quasimodo's clone 16.12.2018 15:46

@Olivier "{${'fn'}(time())}" и "{$fn(time())}" работают точно так же. Оба нуждаются в определенной переменной.

CJ Dennis 05.01.2019 15:48

@CJDennis Поняв ваш ответ, я делюсь своими мыслями- Это означает, что если мы хотим вызвать функцию s внутри Heredoc, тогда мы должны сначала инициализировать переменную s, имея их значения, такие же, как имя функции. Например: -function phpf1(){}, function phpf2(), function phpf3(){}, поэтому, если мы хотим вызвать эти функции внутри heredoc, мы должны создать такие переменные, как $f1= 'phpf1'; $f2= 'phpf2'; $f3= 'phpf3';. Я прав?

Abhishek Kamal 11.02.2020 07:27

@AbhishekKamal Вы могли бы сделать это таким образом, но наличие функции оболочки, которую я установил в своем ответе, делает это ненужным. "{$fn(phpf1())}, {$fn(phpf2())}, {$fn(phpf3())}" - это все, что вам нужно. Все, что может быть допустимым параметром функции, может быть заключено в скобки {$fn()}.

CJ Dennis 11.02.2020 07:46

Начиная с PHP 7.4, fn является зарезервированным словом. php.net/manual/en/migration74.incompatible.php

CJ Dennis 05.05.2020 06:16

Вот хороший пример с использованием предложения @CJDennis:

function double($i)
{ return $i*2; }

function triple($i)
{ return $i*3;}

$tab = 'double';
echo "{$tab(5)} is $tab 5<br>";

$tab = 'triple';
echo "{$tab(5)} is $tab 5<br>";

Например, синтаксис HEREDOC может быть использован для создания огромных форм с отношениями "главный-подробный" в базе данных. Можно использовать функцию HEREDOC внутри элемента управления FOR, добавляя суффикс после имени каждого поля. Это типичная задача на стороне сервера.

вы забываете о лямбда-функции:

$or=function($c,$t,$f){return$c?$t:$f;};
echo <<<TRUEFALSE
    The best color ever is {$or(rand(0,1),'green','black')}
TRUEFALSE;

Вы также можете использовать функцию create_function

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

Я предложил точно такое же решение за 2,5 года до этого. stackoverflow.com/a/10713298/1166898

CJ Dennis 24.02.2018 06:01

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

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

Вы ходили в Хогвартс?

Starx 26.01.2017 13:39

Это работает, потому что false == ''. Определите переменную с именем длины 0 (''). Установите желаемое значение (${''} = date('Y-m-d H:i:s', strtotime('-1 month'))). Отмените его (!) и преобразуйте в переменную (${false}). false нужно преобразовать в строку, а (string)false === ''. Если вы попытаетесь напечатать ложное значение, вместо этого появится ошибка. Следующая строка работает как с правдивыми, так и с ложными значениями, за счет того, что она еще более нечитаема: "${(${''}=date('Y-m-d H:i:s', strtotime('-1 month')))!=${''}}".

CJ Dennis 25.02.2018 13:22

И если вы хотите напечатать NAN, используйте "${(${''} = date('Y-m-d H:i:s', strtotime('-1 month')) )==NAN}".

CJ Dennis 25.02.2018 13:54

<?php
echo <<<ETO
<h1>Hellow ETO</h1>
ETO;

тебе стоит попробовать это . после окончания ВЭТО; команду вы должны дать ввод.

<div><?=<<<heredoc
Use heredoc and functions in ONE statement.
Show lower case ABC = "
heredoc
. strtolower('ABC') . <<<heredoc
".  And that is it!
heredoc
?></div>

Сегодня это немного более элегантно на php 7.x

<?php

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


echo <<<HEREDOC
this is a test: {$test()}
HEREDOC;

Другие вопросы по теме