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






Я бы сделал следующее:
$string = <<< heredoc
plain text and now a function: %s
heredoc;
$string = sprintf($string, testfunction());
Не уверен, что вы считаете это более элегантным ...
Лично я бы вообще не использовал HEREDOC для этого. Это просто не подходит для хорошей системы «построения шаблонов». Весь ваш 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.)
Существует сокращение для echo: <?=$valueToEcho;?> или <%=$valueToEcho;%> в зависимости от ваших настроек INI.
Практически все, что я читал об использовании этих сокращений, говорит, что их использование - плохая практика, и я согласен. Так, к сожалению, если вы пишете код для распространения не может зависеть от этих параметров INI таким образом делая «поддержку» РНР для них тоо для распределенного кода. FWIW, мне приходилось исправлять ошибки в плагинах WordPress других людей не раз, потому что они использовали эти сокращения.
Я согласен, но это странная вещь, на которую можно «жаловаться». Вы в основном говорите: «Жалко, что мне приходится набирать 7 дополнительных символов».
Нет, я не говорю, что жаль, что мне приходится набирать 7 символов; вы неправильно приписываете мои проблемы. Меня беспокоит не набор текста, а чтение. Эти символы создают много визуального шума, что значительно затрудняет сканирование исходного кода и понимание того, что он делает. По крайней мере, для меня МНОГО легче читать HEREDOC. (И, кстати, это 7 символов, сколько бы раз оно ни использовалось в данном фрагменте HTML. Но я отвлекся.)
Краткое содержание приятнее, чище и легче для чтения. По вашему мнению, <?=$title?>много лучше, чем <? Php echo $ title; ?>. Обратной стороной является то, что для распространения многие ini имеют короткие теги. Но, угадайте что ?? Начиная с PHP 5.4, короткие теги включены в PHP независимо от настроек ini! Так что, если вы кодируете с требованием 5.4+ (допустим, вы используете черты характера, например), продолжайте и используйте эти замечательные короткие теги !!
Что такого сложного во встраивании PHP в HTML с правильными разделителями <? Php?>? На читабельность это не влияет. На самом деле, я думаю, что большинство разработчиков, которым не нравится удобочитаемость, пишут плохо сформированный HTML - больше, чем PHP. Просто помните: одна из P в PHP означает «препроцессор». Используйте PHP из-за его сильных сторон и, прежде всего, будьте проще!
Кстати, <? = $ Blah?> Включен в 5.4 по умолчанию, даже если короткие теги отключены.
Получается, что короткий ответ - «Нет». Вы действительно не можете вызвать функцию непосредственно из строки HEREDOC. Мне потребовалось время, чтобы понять это!
@IfediOkonkwo На самом деле, вы можете, и здесь есть несколько ответов, которые показывают, как это сделать. Это просто не считается хорошей практикой.
Я не мог не согласиться с тем, что хочу сделать таким образом «более сложные шаблоны, такие как циклы». Внедрение потока управления в шаблон HTML - это первый шаг к экспоненциальному увеличению сложности. Имеет смысл сначала организовать выходные данные в соответствующих структурах данных, а затем использовать функции вашей коллекции для сопоставления / уменьшения их. Он отлично работает в ReactJS. Вам никогда не понадобится специальный микроязык для создания циклов.
Речь идет о вставке вызовов функций в строки heredoc. Дело не в суждении о том, уместно это или нет. Это суждение для человека, задавшего вопрос. Механизмы создания шаблонов - глупая идея, потому что PHP уже является языком шаблонов.
Это похоже на неправильный ответ на вопрос. Да, это может быть не лучшая практика, но есть ситуации, когда вы действительно хотите это сделать. Однако вопрос не в этом.
Я бы посмотрел на Умный как на механизм шаблонов - я сам не пробовал никаких других, но он мне хорошо помог.
Если вы хотели придерживаться своего текущего подхода к шаблонам без, что плохого в буферизации вывода? Это даст вам гораздо больше гибкости, чем необходимость объявления переменных, которые представляют собой строковые имена функций, которые вы хотите вызвать.
Я немного опоздал, но случайно наткнулся на это. Для будущих читателей вот что я, вероятно, сделал бы:
Я бы просто использовал выходной буфер. Таким образом, вы начинаете буферизацию с помощью 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 для сопоставления метода класса с фактической функцией, которую необходимо вызвать.
Это хорошее решение для тех случаев, когда вы не можете просто добавить шаблонизатор в существующий проект. Спасибо, сейчас пользуюсь.
не следует широко использовать, когда производительность критична: я несколько раз читал, что производительность call_user_func_array хуже, последний раз в комментариях на php.net: php.net/manual/en/function.call-user-func-array.php#97473
Отлично! Мне это нравится, почему я не подумал об этом?!? :-)
Ребята, обратите внимание, что он также работает со строками в двойных кавычках.
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 лучше не иметь переменных с такими же именами, как у любой функции, верно?
Немного поздно, но все же. Это возможно в heredoc!
Загляните в руководство по php, раздел «Сложный (фигурный) синтаксис»
Я уже использую этот синтаксис в первом примере; у него есть недостаток, заключающийся в том, что имя функции помещается в переменную, прежде чем вы сможете вызвать ее внутри фигурных скобок в разделе heredoc, чего я пытался избежать.
Я думаю, что использование 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 () для любых данных, поступающих от пользователей.
Если вы действительно хотите сделать это, но немного проще, чем использование класса, вы можете использовать:
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.
Вы даже можете сделать это: $my_string = "Half the number of seconds since the Unix Epoch: {$fn(time() / 2 . ' Yes! Really!')}";
более компактное определение: $fn = function fn($data) { return $data; };
@devsmt Вы правы. И даже короче: $fn = function ($data) { return $data; };
о, годегольф? хорошо, впустите меня: $fn=function($data){return $data;}; должен быть самым коротким
@ My1 Нет, $f=function($d){return$d;}; короче, но это не Code Golf.
Я даже не знал, что ты можешь вернуться без места
@ My1 Гольф? $fn='strval';
@Olivier "{${'fn'}(time())}" и "{$fn(time())}" работают точно так же. Оба нуждаются в определенной переменной.
@CJDennis Поняв ваш ответ, я делюсь своими мыслями- Это означает, что если мы хотим вызвать функцию s внутри Heredoc, тогда мы должны сначала инициализировать переменную s, имея их значения, такие же, как имя функции. Например: -function phpf1(){}, function phpf2(), function phpf3(){}, поэтому, если мы хотим вызвать эти функции внутри heredoc, мы должны создать такие переменные, как $f1= 'phpf1'; $f2= 'phpf2'; $f3= 'phpf3';. Я прав?
@AbhishekKamal Вы могли бы сделать это таким образом, но наличие функции оболочки, которую я установил в своем ответе, делает это ненужным. "{$fn(phpf1())}, {$fn(phpf2())}, {$fn(phpf3())}" - это все, что вам нужно. Все, что может быть допустимым параметром функции, может быть заключено в скобки {$fn()}.
Начиная с PHP 7.4, fn является зарезервированным словом. php.net/manual/en/migration74.incompatible.php
Вот хороший пример с использованием предложения @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
Для полноты картины можно также использовать !${''}черная магиявзлом парсера:
echo <<<EOT
One month ago was ${!${''} = date('Y-m-d H:i:s', strtotime('-1 month'))}.
EOT;
Вы ходили в Хогвартс?
Это работает, потому что 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')))!=${''}}".
И если вы хотите напечатать NAN, используйте "${(${''} = date('Y-m-d H:i:s', strtotime('-1 month')) )==NAN}".
<?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;
Это не совсем ответ на ваш вопрос, но, учитывая плохую поддержку вызовов функций в операторах heredoc, я обычно просто генерирую строки, которые мне понадобятся, перед печатью heredoc. Затем я могу просто использовать что-то вроде
Text {$string1} Text {$string2} Textв heredoc.