使用Smarty时显示程序执行时间的方法 » 荒野无灯weblog

Keep It Simple, Stupid.

荒野无灯weblog

使用Smarty时显示程序执行时间的方法

当使用Smarty时,似乎没有什么好的方法来实现显示程序执行时间。
WP或者其它程序时都有一个输出程序执行时间的功能,因此,在自己写的程序里,也想实现这一功能。
搜索了一下,发现基本没有这方面的文章。大多数人认为这个没有必要。
本着折腾的精神,开始一行行看Smarty的源码,最终找到一个比较精确计算出程序执行时间的方法。
在程序最开始部分,也就是执行的第一行代码的位置,加上:

define('__START_TIME', microtime(TRUE));

然后在smarty_internal_template.php的 renderTemplate函数第一个ob_start前面加上:

$_SESSION['__excution_time']=microtime(TRUE) - __START_TIME;

完整代码如下:

   public function renderTemplate ()
    {
        if ($this->resource_object->usesCompiler) {
            if ($this->mustCompile() && $this->compiled_template === null) {
                $this->compileTemplateSource();
            } 
            if ($this->smarty->debugging) {
                Smarty_Internal_Debug::start_render($this);
            } 
            $_smarty_tpl = $this;
            //计算执行时间 by 荒野无灯 20110401
            //__START_TIME 在程序开始时定义
            //调用 :{nocache}{$smarty.session.__excution_time|string_format:"%.4f"}{/nocache} 
            $_SESSION['__excution_time']=microtime(TRUE) - __START_TIME;
            ob_start();
            if ($this->resource_object->isEvaluated) {
                eval("?>" . $this->compiled_template);
            } else {
                include($this->getCompiledFilepath ()); 
                // check file dependencies at compiled code
                if ($this->smarty->compile_check) {
                    if (!empty($this->properties['file_dependency'])) {
                        $this->mustCompile = false;
                        $resource_type = null;
                        $resource_name = null;
                        foreach ($this->properties['file_dependency'] as $_file_to_check) {
                            If ($_file_to_check[2] == 'file' || $_file_to_check[2] == 'extends' || $_file_to_check[2] == 'php') {
                                $mtime = filemtime($_file_to_check[0]);
                            } else {
                                $this->getResourceTypeName($_file_to_check[0], $resource_type, $resource_name);
                                $resource_handler = $this->loadTemplateResourceHandler($resource_type);
                                $mtime = $resource_handler->getTemplateTimestampTypeName($resource_type, $resource_name);
                            } 
                            // If ($mtime != $_file_to_check[1]) {
                            If ($mtime > $_file_to_check[1]) {
                                $this->mustCompile = true;
                                break;
                            } 
                        } 
                        if ($this->mustCompile) {
                            // recompile and render again
                            ob_get_clean();
                            $this->compileTemplateSource();
                            ob_start();
                            include($this->getCompiledFilepath ());
                        } 
                    } 
                } 
            } 
        } else {
            if (is_callable(array($this->resource_object, 'renderUncompiled'))) {
                if ($this->smarty->debugging) {
                    Smarty_Internal_Debug::start_render($this);
                } 
                ob_start();
                $this->resource_object->renderUncompiled($this);
            } else {
                throw new SmartyException("Resource '$this->resource_type' must have 'renderUncompiled' methode");
            } 
        } 
        $this->rendered_content = ob_get_clean();
        if (!$this->resource_object->isEvaluated && empty($this->properties['file_dependency'][$this->templateUid])) {
            $this->properties['file_dependency'][$this->templateUid] = array($this->getTemplateFilepath(), $this->getTemplateTimestamp(),$this->resource_type);
        } 
        if ($this->parent instanceof Smarty_Internal_Template) {
            $this->parent->properties['file_dependency'] = array_merge($this->parent->properties['file_dependency'], $this->properties['file_dependency']);
            foreach($this->required_plugins as $code => $tmp1) {
                foreach($tmp1 as $name => $tmp) {
                    foreach($tmp as $type => $data) {
                        $this->parent->required_plugins[$code][$name][$type] = $data;
                    } 
                } 
            } 
        } 
        if ($this->smarty->debugging) {
            Smarty_Internal_Debug::end_render($this);
        } 
        // write to cache when nessecary
        if (!$this->resource_object->isEvaluated && ($this->caching == Smarty::CACHING_LIFETIME_SAVED || $this->caching == Smarty::CACHING_LIFETIME_CURRENT)) {
            if ($this->smarty->debugging) {
                Smarty_Internal_Debug::start_cache($this);
            } 
            $this->properties['has_nocache_code'] = false; 
            // get text between non-cached items
            $cache_split = preg_split("!/\*%%SmartyNocache:{$this->properties['nocache_hash']}%%\*\/(.+?)/\*/%%SmartyNocache:{$this->properties['nocache_hash']}%%\*/!s", $this->rendered_content); 
            // get non-cached items
            preg_match_all("!/\*%%SmartyNocache:{$this->properties['nocache_hash']}%%\*\/(.+?)/\*/%%SmartyNocache:{$this->properties['nocache_hash']}%%\*/!s", $this->rendered_content, $cache_parts);
            $output = ''; 
            // loop over items, stitch back together
            foreach($cache_split as $curr_idx => $curr_split) {
                // escape PHP tags in template content
                $output .= preg_replace('/(<%|%>|<\?php|<\?|\?>)/', '', $curr_split);
                if (isset($cache_parts[0][$curr_idx])) {
                    $this->properties['has_nocache_code'] = true; 
                    // remove nocache tags from cache output
                    $output .= preg_replace("!/\*/?%%SmartyNocache:{$this->properties['nocache_hash']}%%\*/!", '', $cache_parts[0][$curr_idx]);
                } 
            } 
            if (isset($this->smarty->autoload_filters['output']) || isset($this->smarty->registered_filters['output'])) {
                $output = Smarty_Internal_Filter_Handler::runFilter('output', $output, $this);
            }
            // rendering (must be done before writing cache file because of {function} nocache handling)
            $_smarty_tpl = $this;
            ob_start();
            eval("?>" . $output);
            $this->rendered_content = ob_get_clean(); 
            // write cache file content
            $this->writeCachedContent(''. $output. '');
            if ($this->smarty->debugging) {
                Smarty_Internal_Debug::end_cache($this);
            } 
        } else {
            // var_dump('renderTemplate', $this->has_nocache_code, $this->template_resource, $this->properties['nocache_hash'], $this->parent->properties['nocache_hash'], $this->rendered_content);
            if ($this->has_nocache_code && !empty($this->properties['nocache_hash']) && !empty($this->parent->properties['nocache_hash'])) {
                // replace nocache_hash
                $this->rendered_content = preg_replace("/{$this->properties['nocache_hash']}/", $this->parent->properties['nocache_hash'], $this->rendered_content);
                $this->parent->has_nocache_code = $this->has_nocache_code;
            } 
        } 
    } 

这样以后还没完,在同文件buildTemplateFilepath 函数最开始加上上面同样的语句,修改后的函数如下:

 /**
     * get system filepath to template
     */
    public function buildTemplateFilepath ($file = null)
    {
        //计算执行时间 by 荒野无灯 20110401
        //__START_TIME 在程序开始时定义,对于缓存的模板,是不会执行 renderTemplate() 方法的,因此这里再加一次。
        //对于缓存了的模板,getRenderedTemplate() 中会执行 smarty_internal_cacheresource_file.php 中的
        // getCachedContents() ,而 getCachedContents() 会调用 $_template->getCachedFilepath() 来获取缓存文件路径.
        //而 $_template->getCachedFilepath() 在模板未过期或开启缓存的情况下又必须调用 cache_resource_object->getCachedFilepath(),而此方法
        //又要调用 $_template->getTemplateFilepath() ,因此执行终止时间放这里比较合适。基本上是和最终时间很接近了。
        //而此函数又要调用smarty_internal_resource_extends.php的 resource_object->getTemplateFilepath() 
        //调用 :{nocache}{$smarty.session.__excution_time|string_format:"%.4f"}{/nocache} 
        $_SESSION['__excution_time']=microtime(TRUE) - __START_TIME;
//        var_dump('here');exit;

        if ($file == null) {
            $file = $this->resource_name;
        }
        // relative file name? 
        if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $file)) {
            foreach((array)$this->smarty->template_dir as $_template_dir) {
                if (strpos('/\\', substr($_template_dir, -1)) === false) {
                    $_template_dir .= DS;
                } 
                $_filepath = $_template_dir . $file;
                if (file_exists($_filepath)) {
                    return $_filepath;
                }
                if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $_template_dir)) {
                    // try PHP include_path
                    if (($_filepath = Smarty_Internal_Get_Include_Path::getIncludePath($_filepath)) !== false) {
                        return $_filepath;
                    }
                }
            }
        }
        // try absolute filepath
        if (file_exists($file)) return $file;
        // no tpl file found
        if (!empty($this->smarty->default_template_handler_func)) {
            if (!is_callable($this->smarty->default_template_handler_func)) {
                throw new SmartyException("Default template handler not callable");
            } else {
                $_return = call_user_func_array($this->smarty->default_template_handler_func,
                    array($this->resource_type, $this->resource_name, &$this->template_source, &$this->template_timestamp, $this));
                if (is_string($_return)) {
                    return $_return;
                } elseif ($_return === true) {
                    return $file;
                } 
            } 
        } 
        return false;
    } 

最后是在模板中显示了:

{nocache}{$smarty.session.__excution_time|string_format:"%.4f"}{/nocache} seconds

Tagged in : PHP,smarty,exution-time

All Comments (0)
Gravatar image
No Comments