ビューの中で使用できる変数$htmlはどこからくるのか?

環境

この記事の内容は、CakePHP 1.1.12.4205で確認しました。

問題点

CakePHPでは、ビューの中で、例えば、

<?php echo $html->link('New Account', '/accounts/add'); ?>

のように、変数$htmlを使用することができますが、この変数$htmlがどこからきているのか気になったので、調べました。

調査結果

まず、CakePHPにおける基本的な処理の流れを確認します。CakePHPでは、app/webroot/index.phpでリクエストを受けますが、その最後で、

<?php
(略)
         $Dispatcher = new Dispatcher();
         $Dispatcher->dispatch($url);
(略)
?>

として、Dispatcherクラスのdispatchメソッドを呼び出します。Dispatcherクラスは、cake/dispatcher.phpにあります。そのdispatchメソッドを抜き出すと、

<?php
(略)
    function dispatch($url, $additionalParams=array()) {
(略)
        return $this->_invoke($controller, $params, $missingAction);
    }
(略)

であり、_invokeメソッドは、

<?php
(略)
    function _invoke (&$controller, $params, $missingAction = false) {
(略)
            $output = call_user_func_array(array(&$controller, $params['action']), empty($params['pass'])? null: $params['pass']);
(略)
            $output = $controller->render();
(略)
    }
(略)

のように、call_user_func_array関数を利用してコントローラのメソッドを呼び出し、その後、コントローラのrenderメソッドを呼び出しています。renderメソッドは、cake/libs/controller/controller.phpにあります。このメソッドは、

<?php
(略)
    function render($action = null, $layout = null, $file = null) {
(略)
        $this->__viewClass =& new $viewClass($this);
(略)
        return $this->__viewClass->render($action, $layout, $file);
    }
(略)
?>

のようになっており、ビューのクラスを生成して、renderメソッドを呼び出します。var_dump($viewClass)を挿入して実行してみたところ、$viewClassは"View"であることが分かりました。このクラスは、cake/libs/view/view.phpにあります。renderメソッドをみてみます。

<?php
(略)
    function render($action = null, $layout = null, $file = null) {
(略)
                $out = View::_render($viewFileName, $this->viewVars);
(略)
                print $out;
(略)
    }
(略)
?>

このように、renderメソッドでは_renderメソッドを呼び出して、その結果を表示しています(ここでは、一般的な場合に処理されるコードを抜き出しています。場合によっては、違うこともあります)。では次に、_renderメソッドを読みます。

<?php
(略)
    function _render($___viewFn, $___dataForView, $loadHelpers = true, $cached = false) {
        if ($this->helpers != false && $loadHelpers === true) {
            $loadedHelpers = array();
            $loadedHelpers = $this->_loadHelpers($loadedHelpers, $this->helpers);

            foreach(array_keys($loadedHelpers) as $helper) {
                $replace = strtolower(substr($helper, 0, 1));
                $camelBackedHelper = preg_replace('/\\w/', $replace, $helper, 1);

                ${$camelBackedHelper} =& $loadedHelpers[$helper];
(略)
            }
        }
(略)
            include ($___viewFn);
(略)
        $out = ob_get_clean();
(略)
        return $out;
    }
(略)
?>

まず始めにあるif文の中では、ヘルパーを読み込んでいます。ここで今回注目すべきところが、

<?php
(略)
                ${$camelBackedHelper} =& $loadedHelpers[$helper];
(略)
?>

の文です。$camelBackedHelper変数には、"html"といった文字列が設定されています。つまり上の文は、

<?php
(略)
                $html =& $loadedHelpers[$helper];
(略)
?>

と同じになります(foreach文の中にあるので、もちろん場合によります)。foreach文で初めて設定される変数ですが、PHPはforeach文の中だけのスコープは持たないので、この変数はforeach文を出た後でも有効です。その後、include ($___viewFn);でビューのファイル(*.thtmlです)を読み込み、HTMLを出力します。以上が、ビューの中で$html変数が使える理由です。