HEREDOC文字列内でのPHP関数の呼び出し


91

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スタイルを反転させる必要があります。それは悪いことではありませんが、それは私の慣性を説明します。


3
これは厳密にはあなたの質問への回答ではありませんが、ヒアドキュメントのステートメントでの関数呼び出しのサポートが不十分であることを考えると、私は通常、ヒアドキュメントを印刷する前に必要な文字列を生成するだけです。次に、Text {$string1} Text {$string2} Textヒアドキュメントのようなものを使用できます。
rinogo 2018年

回答:


51

個人的には、これにはHEREDOCをまったく使用しません。これは、優れた「テンプレート作成」システムにはなりません。すべてのHTMLが文字列にロックされていますが、いくつかの欠点があります

  • WYSIWYGのオプションなし
  • IDEからのHTMLのコード補完なし
  • ロジックファイルにロックされた出力(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');

8
echoの省略形があります:<?=$valueToEcho;?>または<%=$valueToEcho;%>INI設定に依存します。
Peter Bailey

3
私がそれらの略記を使用することについて読んだほとんどすべては、それらを使用することは悪い習慣であると言っています、そして私は同意します。残念ながら、配布用のコードを作成している場合、それらのINI設定に依存することはできません。そのため、それらのPHPの「サポート」は、配布されたコードに対して無効になります。FWIW、私は他の人のWordPressプラグインのバグを修正する必要がありました。なぜなら、彼らはこれらの省略形を使用したからです。
MikeSchinkel 2012

1
いいえ、7文字入力しなければならないのは残念だと言っているのではありません。あなたは私の問題を誤って帰属します。それは私が気にしているタイピングではなく、リーディングです。これらの文字は多くの視覚的なノイズを作成し、ソースコードをスキャンしてコードの動作を理解することをはるかに困難にします。私にとっては、少なくともされているMUCHヒアドキュメントを読みやすく。(そしてBTWは、特定のHTMLフラグメントで使用される回数が7文字です。しかし、私は
余談

12
短い方が見やすく、読みやすく、読みやすくなっています。あなたの見解で<?=$title?>は、<?php echo $ titleよりもはるかに優れています。?>。欠点は、はい、配布のために多くのiniが短いタグをオフにしていることです。しかし、何を推測しますか?とおりPHP 5.4、短いタグがiniファイルの設定にかかわらず、PHPで有効になっています!したがって、5.4以上の要件でコーディングしている場合(たとえば、特性を使用しているとしましょう)、先に進んでこれらの素晴らしい短いタグを使用してください。
神保

2
ちなみに、<?= $ blah?>は、短いタグがオフになっていても、5.4ではデフォルトで有効になっています。
callmetwan 2014年

72

本当にこれをやりたいが、クラスを使用するよりも少し簡単な場合は、以下を使用できます。

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

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

素晴らしい@CJDennis!これは、HEREDOC内で関数呼び出しを使用するための最良かつ最もクリーンなソリューションです。状況によっては素晴らしいリソースがあります。私のサイトでは、22行のフィールドセット(FORループ内のHEREDOCブロック)でフォームを生成するためにHEREDOCを使用し、tabindex位置を生成するために関数を呼び出しています。
Paulo Buchsbaum 2013年

あなたもこれを行うことができます:$my_string = "Half the number of seconds since the Unix Epoch: {$fn(time() / 2 . ' Yes! Really!')}";
CJデニス

2
よりコンパクトな定義: $fn = function fn($data) { return $data; };
devsmt 2016

1
@devsmtその通りです。そして、さらに短いです:$fn = function ($data) { return $data; };
CJデニス

ああ、ゴデゴルフ?$fn=function($data){return $data;};
はい

42

私は次のようにします:

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

これをよりエレガントに考えるかどうかはわかりません...


17

これを試してください(グローバル変数として、または必要なときにインスタンス化してください):

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

  $fn = new Fn();
?>

これで、すべての関数呼び出しが$fnインスタンスを通過します。したがって、既存の関数testfunction()は、ヒアドキュメントで次のように呼び出すことができます{$fn->testfunction()}

基本的に、すべての関数をクラスインスタンスにラップし、PHPの__call magicメソッドを使用して、呼び出される必要がある実際の関数にクラスメソッドをマッピングします。


2
これは、既存のプロジェクトにテンプレートエンジンを追加できない場合に適したソリューションです。ありがとう、今使っています。
ブランドン、

パフォーマンスが重要な場合は広く使用しないcall_user_func_arrayでください。前回
Markus、

いいね!私はそれが好きです、なぜ私はこれを考えなかったのですか?:-)
MikeSchinkel 2012

10

完全を期すために、!${''} 黒魔術 パーサーハックを使用することもできます。

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

7
ホグワーツに行きましたか?
Starx

これは機能し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デニス

また、印刷する場合はNAN、を使用します"${(${''} = date('Y-m-d H:i:s', strtotime('-1 month')) )==NAN}"
CJデニス

9

少し遅れましたが、偶然見つけました。将来の読者のために、私がおそらく何をするかをここに示します。

私は出力バッファを使用します。したがって、基本的には、ob_start()を使用してバッファリングを開始し、その中に「テンプレートファイル」に関数や変数などを含め、バッファの内容を取得して文字列に書き込み、バッファを閉じます。次に、必要な変数をすべて使用し、任意の関数を実行でき、IDEでHTML構文の強調表示を使用できます。

これが私の意味です:

テンプレートファイル:

<?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

このスニペットは、userscope内で定義された関数の名前で変数を定義し、同じ名前を含む文字列にバインドします。実演させてください。

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

6

ここにラッピング機能を持つ素晴らしい解決策を見つけました: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
私はこれの2.5年前にまったく同じソリューションを提案しました。stackoverflow.com/a/10713298/1166898
CJデニス

5

ヒアドキュメントの使用は、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;

残念ながら、質問であなたが関数を変数にバインドすることは良い提案でしたが、結局、それは価値のないコードに複雑さのレベルを追加し、コードを読みにくくします。ヒアドキュメントの主な利点。


2
過去4年間で、これは他のほとんどのアプローチよりもはるかに賢いことが証明されました。テンプレートで構成を使用し(小さなページで構成される大きなページを構築)、すべての制御ロジックを個別に維持することは、テンプレート作成に真剣に取り組むすべての人にとって標準的なアプローチです。私は好きではありませんが、学問的には健全です)。私が作成する唯一のスタイルのメモ:主に読みやすさの一貫性を保ち、後で事故を避けるために、常に変数の周りに{}を使用します。また、ユーザーからのデータをhtmlspecialchars()で送信することを忘れないでください。
カリブーのジョシュ、2015

4

私はSmartyをテンプレートエンジンとして見てみます。自分で他のエンジンを試したことはありませんが、うまくいきました。

テンプレートではなく現在のアプローチを使い続けたい場合、出力バッファリングの何が悪いのでしょうか?呼び出したい関数の文字列名である変数を宣言するよりもはるかに柔軟性があります。


3

あなたはラムダ関数について忘れています:

$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を使用することもできます


2

少し遅れますが、まだです。これはヒアドキュメントで可能です!

PHPマニュアルの「複雑な(中)構文」セクションをご覧ください。


最初の例ではすでにその構文を使用しています。これには、ヒアドキュメントセクションの波括弧内で呼び出す前に、関数名を変数に入れておくという欠点があります。これは、回避しようとしていたことです。
Doug Kavendek

2

@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構文の適切な使用法は、データベースに主従関係を持つ巨大なフォームを生成することです。FORコントロール内でHEREDOC機能を使用して、各フィールド名の後にサフィックスを追加できます。これは典型的なサーバー側のタスクです。



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


0

これは今日のphp 7.xではもう少しエレガントです

<?php

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


echo <<<HEREDOC
this is a test: {$test()}
HEREDOC;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.