質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Twig

Twig は、簡潔で可読性の高いテンプレートを記述することができ、 シンプルに記述することを目的として作られた PHPテンプレートエンジンです。

Q&A

解決済

1回答

1981閲覧

Twig の registerUndefinedFunctionCallback() の仕様について

ValveHead

総合スコア6

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Twig

Twig は、簡潔で可読性の高いテンプレートを記述することができ、 シンプルに記述することを目的として作られた PHPテンプレートエンジンです。

1グッド

0クリップ

投稿2018/06/10 04:54

編集2018/06/21 12:30

はじめて質問させていただきます。どうぞよろしくお願いいたします。

テンプレートエンジンの Twig 上で PHP の組み込み関数を使用できるようにするため、
(方法は複数あるようですが)こちらなどを参考に、次のようなコードを書きました。

↓index.twig↓

html

1<html> 2<head> 3 <meta charset="UTF-8"> 4 <title>{{ title }}</title> 5</head> 6<body> 7 <h1>welcome to {{ message }}</h1> 8 <h2>welcome to {{ substr(message, 0, -6) }}</h2> 9 <h2>welcome to {{ str_replace('ground', 'place', message)}}</h2> 10</body> 11</html>

↓tiwg_test.php↓

php

1<?php 2require_once './vendor/autoload.php'; 3 4$loader = new Twig_Loader_Filesystem('./views/'); 5$twig = new Twig_Environment($loader); 6 7$twig->registerUndefinedFunctionCallback(function ($name) { 8 if (function_exists($name)) { 9 return new Twig_SimpleFunction($name, $name); 10 } 11 12 return false; 13}); 14 15echo $twig->render('index.twig', array( 16'title' => 'Twig Test', 17'message' => 'underground' 18));

これによって、以下の結果を得ることができました。

result

ただ、不明な点があります。

###registerUndefinedFunctionCallback() はいったい何をしているのか?
Twig_Environment クラスが書かれている Environment.php を確認すると、次のようになっていました。

php

1public function registerUndefinedFunctionCallback($callable) 2{ 3 $this->functionCallbacks[] = $callable; 4}

$functionCallbacks はクラス内で、

protected $functionCallbacks = array();

と宣言されています。

クラス内で $functionCallbacks が他に出てくるのは、以下の関数のみです(一番最後の foreach 文)。

php

1public function getFunction($name) 2{ 3 if (!$this->extensionInitialized) { 4 $this->initExtensions(); 5 } 6 7 if (isset($this->functions[$name])) { 8 return $this->functions[$name]; 9 } 10 11 foreach ($this->functions as $pattern => $function) { 12 $pattern = str_replace('\*', '(.*?)', preg_quote($pattern, '#'), $count); 13 14 if ($count) { 15 if (preg_match('#^'.$pattern.'$#', $name, $matches)) { 16 array_shift($matches); 17 $function->setArguments($matches); 18 19 return $function; 20 } 21 } 22 } 23 24 foreach ($this->functionCallbacks as $callback) { 25 if (false !== $function = call_user_func($callback, $name)) { 26 return $function; 27 } 28 }

この getFunction() はクラス内では呼ばれていません。
コンストラクタ(必要であれば記載します)も確認しましたが、getFunction() や $functionCallbacks に結びつくものは現状見つけることができていません(そもそもコードの読み方がおかしいでしょうか?)。

registerUndefinedFunctionCallback() は、いったいどのようにして index.twig から PHP の組み込み関数を読み取って、Twig で使えるようにしているのでしょうか?

また、初歩的な質問になってしまうかもしれませんが、

php

1$twig->registerUndefinedFunctionCallback(function ($name) { 2 if (function_exists($name)) { 3 return new Twig_SimpleFunction($name, $name); 4 }

上記のコールバック関数の引数となっている $name はどこからやってくるのでしょうか?

以上の 2 点について、ご回答をいただけましたら幸いです。
よろしくお願いいたします。

m.ts10806👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

えっと、luckerお兄さん、いつもどおり酔っ払ってるから変な事言ったらごめんね。

良い子の知りたいことは
> registerUndefinedFunctionCallback() は、いったいどのようにして index.twig から PHP の組み込み関数を読み取って、Twig で使えるようにしているのでしょうか?
って事だと思うんだけど、これ、すごく簡単。

ここ。

PHP

1$twig->registerUndefinedFunctionCallback(function ($name) { 2 if (function_exists($name)) { 3 return new Twig_SimpleFunction($name, $name); 4 } 5 6 return false; 7});

function_exists()っていうのはTwigではなくPHPの標準の関数で、指定された関数が定義されているか調べる関数ね。
function_exists

Twigでテンプレートをパースしている過程で関数と思われる名前、例えば

HTML

1<h2>welcome to {{ substr(message, 0, -6) }}</h2>

で言ったら、substrというのが見つかった場合、その関数がまだTwigに登録されていなかったらregisterUndefinedFunctionCallback(callable $callable)で記述されてる$callableが呼ばれる。

$callable として登録されてるのは、こういうラムダ式。

PHP

1function ($name) { 2 if (function_exists($name)) { 3 return new Twig_SimpleFunction($name, $name); 4 } 5 6 return false; 7}

このラムダの$nameに、さっきの例では"substr"が渡される。そうすると

PHP

1if (function_exists($name)) { 2 return new Twig_SimpleFunction($name, $name); 3}

が評価されて、"substr" がPHPで定義されている関数なら、Twig_SimpleFunctionのインスタンスを生成して返す。第一引数はTwigに登録する関数名、第二引数はその関数名がテンプレートに出てきた時に処理を任せるcallable。

ここで晴れて"substr"はTwigで認識できる関数として登録されるから、以後、テンプレートの中で"substr()"が見つかったら、今生成したTwig_SimpleFunctionインスタンスに従って、そのcallableに処理を任せる、というわけ。

で、さっきのfunction_exists($name)で$nameがPHPの標準関数ですらなかった場合、falseが返される。

そうするとTwigは、「そんな関数どこにも登録されてねーよ」と言って、エラーメッセージを出すことになるわけ。

Could you understand?

投稿2018/06/10 09:25

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/06/10 09:29

んで、 protected $functionCallbacks = array(); になってるから、 今まで認識されていない関数っぽいものが見つかるたびに、上記で評価して、PHP組み込み関数であったらその配列$functionCallbacksに1つずつ追加していくわけ。 で、関数っぽいのが見つかるたびに、その配列をチェックして、登録されているか調べ、されていなかったら同じ事の繰り返しになるってことだね。
ValveHead

2018/06/10 13:27

lucker さん、ご回答をありがとうございます。 追加でいくつかお聞きしてもよいでしょうか。 >で言ったら、substrというのが見つかった場合、その関数がまだTwigに登録されていなかったら registerUndefinedFunctionCallback(callable $callable)で記述されてる$callableが呼ばれる。 この例で言えば「substr がまだ Twig に登録されていない」というのは、どのように判断されるのでしょうか(registerUndefinedFunctionCallback() は 見つけた組み込み関数を $functionCallbacks に代入するだけの存在という理解で問題ないでしょうか。$functionCallbacks の中身を確認するのは誰なのでしょう?)。 また、substr() の機能そのものを呼び出す仕組みがよくわかりません。Twig_SimpleFunction インスタンスを生成するときに指定した第 2 引数は、コンストラクタによってインスタンス内の $callable に代入されるようですが、なぜそれだけの操作で substr() が使えるようになるのでしょうか。 何か見当違いなことを言っていたらすみません。 ご回答のほど、どうぞよろしくお願いいたします。
退会済みユーザー

退会済みユーザー

2018/06/11 12:26

>この例で言えば「substr がまだ Twig に登録されていない」というのは、どのように判断されるのでしょうか 記憶で話すので申し訳ないけど、Twigに独自関数登録するときは、 $function = new Twig_SimpleFunction('my_function', function () { echo "This is my function!"; }); $twig->addFunction($function); みたいにTwig_SimpleFunctionクラスのインスタンスを登録するんだよね。 で、addFunction()に渡されたインスタンスは配列に格納されてて、その配列を漁って登録されてないか調べてる感じ。
退会済みユーザー

退会済みユーザー

2018/06/11 12:30

>registerUndefinedFunctionCallback() は 見つけた組み込み関数を $functionCallbacks に代入するだけの存在という理解で問題ないでしょうか。 違うね。registerUndefinedFunctionCallback() は、まだ登録されていない関数っぽいのが見つかった時に、それがPHPの組み込み関数ならTwig_SimpleFunctionクラスのインスタンスを生成して返す関数を、Twigに登録する存在。 $functionCallbacksに格納してるのは別の人。
退会済みユーザー

退会済みユーザー

2018/06/11 12:44

>Twig_SimpleFunction インスタンスを生成するときに指定した第 2 引数は、コンストラクタによってインスタンス内の $callable に代入されるようですが、なぜそれだけの操作で substr() が使えるようになるのでしょうか。 Twig_SimpleFunction インスタンスを生成する時に、第一引数が見つかった関数名のstring、第二引数がcallableなんだけど、callableって何かって言うと、ラムダ式とか無名関数とか言われてるやつ。 例えばこんな感じで $callable = function($hoge){ echo $hoge; }; 関数そのものを変数に登録して $callable("test"); って呼び出す事ができる。つまり、Twig_SimpleFunctionのインスタンスの関数名として "substr" が登録されいて、callable として PHP の substr 関数そのものを登録してしまう。 あとは Twig でテンプレートをパースしていく過程で関数っぽい物 substr(string $string , int $start [, int $length ] )が見つかったら、登録してある関数配列をforeachかなんかで漁って関数名がsubstrとしてマッチしたらそのインスタンスのcallableに引数として(string $string , int $start [, int $length ] )を渡し、結果をテンプレートに埋め込む。 という感じなんだけど、
退会済みユーザー

退会済みユーザー

2018/06/11 12:45

詳しくはコード読まないと正確な記述はできなくて、やるとしたらこの週末くらいにならないと時間取れないな。
退会済みユーザー

退会済みユーザー

2018/06/11 12:48

あとひとつだけ >上記のコールバック関数の引数となっている $name はどこからやってくるのでしょうか? $twig->registerUndefinedFunctionCallback(function ($name) { if (function_exists($name)) { return new Twig_SimpleFunction($name, $name); } この$nameね。 これは、Twigがテンプレートをパースしてる段階で見つかった関数っぽい名前が渡される。 もし正確に知りたかったら、今週末 lucker お兄さんが暇になることを祈るといいよ。
ValveHead

2018/06/11 15:52

lucker さん、詳細にご説明くださり、ありがとうございます。 十分に理解できているかどうかは怪しいですが、少なくとも流れは把握できました。 ウキウキでプログラミングを独学していたのに、ふと寄り道したテンプレートエンジンで心を折られるところでした……。 >詳しくはコード読まないと正確な記述はできなくて、やるとしたらこの週末くらいにならないと時間取れないな。 さすがに次の週末までお時間を割かせてしまうのは申し訳ないので、 差し支えなければ、そろそろこの質問を閉じさせていただこうかと思います。 ただ、最後に 2 点だけ、お付き合い願えたら幸いです。 >つまり、Twig_SimpleFunctionのインスタンスの関数名として "substr" が登録されていて、callable として PHP の substr 関数そのものを登録してしまう。 これは、イメージとしては、次のように登録されるということでしょうか。 $substr = function(string $string , int $start [, int $length ] ) { substr の処理 } また「callable として PHP の substr 関数そのものを登録」といっても、登録対象となる substr 関数そのものを Twig はどうやって引っ張ってくるのでしょうか(登録した"後"にどうやって呼び出すのかについては、先のご回答のおかげで把握できました)。 やはり Twig 本体のコード次第ということでしょうか。 どうぞよろしくお願いいたします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問