对于变量$output为啥能取得栏目的值不理解
在后台中只要输入栏目,下面的代码就能循环出栏目来,逻辑顺序是这样的:
<?php if(!empty($output['navigation_list']) && is_array($output['navigation_list'])) {?>
      <?php foreach($output['navigation_list'] as $value) {?>
      <li class="link"><a href="<?php echo $value['navigation_link'];?>" <?php echo $value['navigation_open_type']=='1'?'target="_blank"':'';?>><?php echo $value['navigation_title'].'111111';?></a></li>
      <?php } ?>
      <?php } ?>
// output dir
$output = XSUtil::getOpt('o', 'output', true);
if ($output === null) {
$output = '.';
}
if (!is_dir($output)) {
echo "错误:输出目录 ($output) 不是一个有效的目录。\n";
exit(-1);
}
if (!is_writable($output)) {
echo "错误:输出目录 ($output) 不可写入,请注意检查权限。\n";
exit(-1);
}
/**
 * 取得命令行参数
 * 要求事先调用 parseOpt, 否则会自动以默认参数调用它。
 * @param string $short 短参数名
 * @param string $long 长参数名
 * @param bool $extra 是否补用默认顺序的参数
 * @return string 返回可用的参数值,若不存在则返回 null
 * @see parseOpt
 */
public static function getOpt($short, $long = null, $extra = false)
{
if (self::$options === null) {
self::parseOpt();
} $value = null;
$options = self::$options;
if ($long !== null && isset($options[$long])) {
$value = $options[$long];
} elseif ($short !== null && isset($options[$short])) {
$value = $options[$short];
} elseif ($extra === true && isset($options['-'][self::$optind])) {
$value = $options['-'][self::$optind];
self::$optind++;
}
return $value;
}

解决方案 »

  1.   

    getOpt()函数内部有两分支
    self::$options  
    self::parseOpt()
    顺着这两个分支继续跟一下
      

  2.   

    XSUtil::getOpt 中对返回变量 $value 赋了值,所以
    $output = XSUtil::getOpt('o', 'output', true); 
    有值
      

  3.   

    干脆我把这个类帖出来,你看一下
    <?php
    /**
     * XSUtil 类定义文件
     *
     * @author hightman
     * @link http://www.xunsearch.com/
     * @copyright Copyright &copy; 2011 HangZhou YunSheng Network Technology Co., Ltd.
     * @license http://www.xunsearch.com/license/
     * @version $Id$
     *//**
     * XSUtil 工具程序通用代码
     * 
     * @author hightman <[email protected]>
     * @version 1.0.0
     * @package XS.util
     */
    class XSUtil
    {
    private static $optind, $options = null;
    private static $charset = null; /**
     * 修正字符串至固定宽度
     * 其中一个全角符号、汉字的宽度为半角字符的 2 倍。
     * @param string $text 要修正的字符串
     * @param int $size 修正的目标宽度
     * @param string $pad 用于填充补足的字符
     * @return type 
     */
    public static function fixWidth($text, $size, $pad = ' ')
    {
    for ($i = $j = 0; $i < strlen($text) && $j < $size; $i++, $j++) {
    if ((ord($text[$i]) & 0xe0) === 0xe0) {
    if (($size - $j) == 1) {
    break;
    }
    $j++;
    $i += 2;
    }
    }
    return substr($text, 0, $i) . str_repeat($pad, $size - $j);
    } /**
     * 设置输出、输入编码
     * 默认输出的中文编码均为 UTF-8
     * @param string $charset 期望得到的字符集
     */
    public static function setCharset($charset)
    {
    if ($charset !== null && strcasecmp($charset, 'utf8') && strcasecmp($charset, 'utf-8')) {
    self::$charset = $charset;
    ob_start(array(__CLASS__, 'convertOut'));
    }
    } /**
     * 把 UTF-8 字符串转换为用户编码
     * @param string $buf 要转换字符串
     * @return string 转换后的字符串
     */
    public static function convertOut($buf)
    {
    if (self::$charset !== null) {
    return XS::convert($buf, self::$charset, 'UTF-8');
    }
    return $buf;
    } /**
     * 把用户输入的字符串转换为 UTF-8 编码
     * @param string $buf 要转换字符串
     * @return string 转换后的字符串
     */
    public static function convertIn($buf)
    {
    if (self::$charset !== null) {
    return XS::convert($buf, 'UTF-8', self::$charset);
    }
    return $buf;
    } /**
     * 解析命令行参数
     * @param array $valued 需要附加值的参数列表
     * @return array 解析完的参数数组,未指定 - 开头的选项统一放入 '-' 的子数组
     */
    public static function parseOpt($valued = array())
    {
    $result = array('-' => array());
    $params = isset($_SERVER['argv']) ? $_SERVER['argv'] : array();
    for ($i = 0; $i < count($params); $i++) {
    if ($params[$i] === '--') {
    for ($i = $i + 1; $i < count($params); $i++) {
    $result['-'][] = $params[$i];
    }
    break;
    } elseif ($params[$i][0] === '-') {
    $value = true;
    $pname = substr($params[$i], 1);
    if ($pname[0] === '-') {
    $pname = substr($pname, 1);
    if (($pos = strpos($pname, '=')) !== false) {
    $value = substr($pname, $pos + 1);
    $pname = substr($pname, 0, $pos);
    }
    } elseif (strlen($pname) > 1) {
    for ($j = 1; $j < strlen($params[$i]); $j++) {
    $pname = substr($params[$i], $j, 1);
    if (in_array($pname, $valued)) {
    $value = substr($params[$i], $j + 1);
    break;
    } elseif (($j + 1) != strlen($params[$i])) {
    $result[$pname] = true;
    }
    }
    }
    if ($value === true && in_array($pname, $valued) && isset($params[$i + 1])) {
    $value = $params[$i + 1];
    $i++;
    }
    $result[$pname] = $value;
    } else {
    $result['-'][] = $params[$i];
    }
    }
    self::$options = $result;
    self::$optind = 1;
    return $result;
    } /**
     * 取得命令行参数
     * 要求事先调用 parseOpt, 否则会自动以默认参数调用它。
     * @param string $short 短参数名
     * @param string $long 长参数名
     * @param bool $extra 是否补用默认顺序的参数
     * @return string 返回可用的参数值,若不存在则返回 null
     * @see parseOpt
     */
    public static function getOpt($short, $long = null, $extra = false)
    {
    if (self::$options === null) {
    self::parseOpt();
    } $value = null;
    $options = self::$options;
    if ($long !== null && isset($options[$long])) {
    $value = $options[$long];
    } elseif ($short !== null && isset($options[$short])) {
    $value = $options[$short];
    } elseif ($extra === true && isset($options['-'][self::$optind])) {
    $value = $options['-'][self::$optind];
    self::$optind++;
    }
    return $value;
    } /**
     * 刷新标准输出缓冲区
     */
    public static function flush()
    {
    flush();
    if (ob_get_level() > 0) {
    ob_flush();
    }
    } /**
     * 拷贝一个目录及其子目录文件
     */
    public static function copyDir($src, $dst)
    {
    if (!($dir = @dir($src)) || (!is_dir($dst) && !@mkdir($dst, 0755, true))) {
    return false;
    }
    while (($entry = $dir->read()) !== false) {
    if ($entry === '.' || $entry === '..') {
    continue;
    }
    $psrc = $src . DIRECTORY_SEPARATOR . $entry;
    $pdst = $dst . DIRECTORY_SEPARATOR . $entry;
    if (is_dir($pdst)) {
    self::copyDir($psrc, $pdst);
    } else {
    @copy($psrc, $pdst);
    }
    }
    $dir->close();
    return true;
    }
    }
      

  4.   


    我之前的表述有误。并不是两个分支
    而是
    先检查是否有options,如果没有,则会执行parseopt()生成配置数组。
    所以你应该跟踪parseOpt()的具体实现。
    简单的打印log可以轻松跟踪代码的执行流程。
      

  5.   


    我之前的表述有误。并不是两个分支
    而是
    先检查是否有options,如果没有,则会执行parseopt()生成配置数组。
    所以你应该跟踪parseOpt()的具体实现。
    简单的打印log可以轻松跟踪代码的执行流程。
    你说的self:arseOpt()是下面这一函数,这个如何打印跟踪呢?
    /**
     * 解析命令行参数
     * @param array $valued 需要附加值的参数列表
     * @return array 解析完的参数数组,未指定 - 开头的选项统一放入 '-' 的子数组
     */
    public static function parseOpt($valued = array())
    {
    $result = array('-' => array());
    $params = isset($_SERVER['argv']) ? $_SERVER['argv'] : array();
    for ($i = 0; $i < count($params); $i++) {
    if ($params[$i] === '--') {
    for ($i = $i + 1; $i < count($params); $i++) {
    $result['-'][] = $params[$i];
    }
    break;
    } elseif ($params[$i][0] === '-') {
    $value = true;
    $pname = substr($params[$i], 1);
    if ($pname[0] === '-') {
    $pname = substr($pname, 1);
    if (($pos = strpos($pname, '=')) !== false) {
    $value = substr($pname, $pos + 1);
    $pname = substr($pname, 0, $pos);
    }
    } elseif (strlen($pname) > 1) {
    for ($j = 1; $j < strlen($params[$i]); $j++) {
    $pname = substr($params[$i], $j, 1);
    if (in_array($pname, $valued)) {
    $value = substr($params[$i], $j + 1);
    break;
    } elseif (($j + 1) != strlen($params[$i])) {
    $result[$pname] = true;
    }
    }
    }
    if ($value === true && in_array($pname, $valued) && isset($params[$i + 1])) {
    $value = $params[$i + 1];
    $i++;
    }
    $result[$pname] = $value;
    } else {
    $result['-'][] = $params[$i];
    }
    }
    self::$options = $result;
    self::$optind = 1;
    return $result;
    }
      

  6.   


    $output = XSUtil::getOpt('o', 'output', true);这里有值。
      

  7.   

    我好象搞错了,又查了一下。我这个问题是这样的:再说一下,我的目的是想查出这个导航的源头在哪定义的。
    不过他的代码写的很怪。
    这次查到了线索:下面是它的追踪路线
    先调用这个函数
    /**
     * 获取导航
     */
    Tpl::output('nav_list',($nav = F('nav'))? $nav :H('nav',true,'file'));
    下面是这个函数的具体写法
    /**
     * 抛出变量
     *
     * @param mixed $output
     * @param  void
     */
    public static function output($output,$input=''){
    self::getInstance();

    self::$output_value[$output] = $input;
    }
    上面函数的分支函数具体写法
    /**
     * 实例化
     *
     * @return obj
     */
    public static function getInstance(){
    if (self::$instance === null || !(self::$instance instanceof Tpl)){
    self::$instance = new Tpl();
    }
    return self::$instance;
    }
    /**
     * 输出模板内容的数组,其他的变量不允许从程序中直接输出到模板
     */
    private static $output_value = array();
    生成导航需要的函数
    /**
     * 文件数据读取和保存 字符串、数组
     *
     * @param string $name 文件名称(不含扩展名)
     * @param mixed $value 待写入文件的内容
     * @param string $path 写入cache的目录
     * @param string $ext 文件扩展名
     * @return mixed
     */
    function F($name, $value = null, $path = 'cache', $ext = '.php') {
    if (strtolower(substr($path,0,5)) == 'cache'){
    $path  = 'data/'.$path;
    }
    static $_cache = array();
    if (isset($_cache[$name.$path])) return $_cache[$name.$path];
        $filename = BASE_ROOT_PATH.'/'.$path.'/'.$name.$ext;
        if (!is_null($value)) {
            $dir = dirname($filename);
            if (!is_dir($dir)) mkdir($dir);
            return write_file($filename,$value);
        }    if (is_file($filename)) {
            $_cache[$name.$path] = $value = include $filename;
        } else {
            $value = false;
        }
        return $value;
    }
    /**
     * 读/写 缓存方法
     *
     * H('key') 取得缓存
     * H('setting',true) 生成缓存并返回缓存结果
     * H('key',null) 清空缓存
     * H('setting',true,'file') 生成商城配置信息的文件缓存
     * H('setting',true,'memcache') 生成商城配置信息到memcache
     * @param string $key 缓存名称
     * @param string $value 缓存内容
     * @param string $type 缓存类型,允许值为 file,memcache,xcache,apc,eaccelerator,可以为空,默认为file缓存
     * @param int/null $expire 缓存周期
     * @param mixed $args 扩展参数
     * @return mixed
     */
    function H($key, $value='', $cache_type='', $expire=null, $args=null){
    static $cache = array();
    $cache_type = $cache_type ? $cache_type : 'file';
    $obj_cache = Cache::getInstance($cache_type,$args);
        if ($value !== '') {
            if (is_null($value)) { // 删除缓存
                $result = $obj_cache->rm($key);
                if ($result)
                    unset($cache[$cache_type . '_' . $key]);
                return $result;
            }else { // 缓存数据
             if ($value === true) $obj_cache->rm($key);
                $list = Model('cache')->call($key);
                $obj_cache->set($key, $list, null, $expire);
                $cache[$cache_type . '_' . $key] = $list;
            }
            return $value === true ? $list : true;
        }
        if (isset($cache[$cache_type . '_' . $key]))
            return $cache[$cache_type . '_' . $key];    $value = $obj_cache->get($key); // 取得缓存
        $cache[$cache_type . '_' . $key] = $value;
        return $value;
    }就是上面这些了,不过就是知道这些,我也看不出来,为啥它用$output这个数组就能取出所有导航呢
      

  8.   

    干脆我把模板类帖出来吧,这个导航主要是用这个模板类里面的函数
    <?php
    /**
     * 模板驱动
     *
     * 模板驱动,商城模板引擎
     *
     *
     * @package    tpl
     * @copyright  Copyright (c) 2007-2013 ShopNC Inc. (http://www.shopnc.net)
     * @license    http://www.shopnc.net
     * @link       http://www.shopnc.net
     * @author    ShopNC Team
     * @since      File available since Release v1.1
     */
    defined('InShopNC') or exit('Access Invalid!');
    class Tpl{
    /**
     * 单件对象
     */
    private static $instance = null;
    /**
     * 输出模板内容的数组,其他的变量不允许从程序中直接输出到模板
     */
    private static $output_value = array();
    /**
     * 模板路径设置
     */
    private static $tpl_dir='';
    /**
     * 默认layout
     */
    private static $layout_file = 'layout';

    private function __construct(){}

    /**
     * 实例化
     *
     * @return obj
     */
    public static function getInstance(){
    if (self::$instance === null || !(self::$instance instanceof Tpl)){
    self::$instance = new Tpl();
    }
    return self::$instance;
    }

    /**
     * 设置模板目录
     *
     * @param string $dir
     * @return bool
     */
    public static function setDir($dir){
    self::$tpl_dir = $dir;
    return true;
    }
    /**
     * 设置布局
     *
     * @param string $layout
     * @return bool
     */
    public static function setLayout($layout){
    self::$layout_file = $layout;
    return true;
    }

    /**
     * 抛出变量
     *
     * @param mixed $output
     * @param  void
     */
    public static function output($output,$input=''){
    self::getInstance();

    self::$output_value[$output] = $input;
    }

    /**
     * 调用显示模板
     *
     * @param string $page_name
     * @param string $layout
     * @param int $time
     */
    public static function showpage($page_name='',$layout='',$time=2000){
    if (!defined('TPL_NAME')) define('TPL_NAME','default');
    self::getInstance();
    if (!empty(self::$tpl_dir)){
    $tpl_dir = self::$tpl_dir.DS;
    }
    //默认是带有布局文件
    if (empty($layout)){
    $layout = 'layout'.DS.self::$layout_file.'.php';
    }else {
    $layout = 'layout'.DS.$layout.'.php';
    }
    $layout_file = BASE_PATH.'/templates/'.TPL_NAME.DS.$layout;
    $tpl_file = BASE_PATH.'/templates/'.TPL_NAME.DS.$tpl_dir.$page_name.'.php';
    if (file_exists($tpl_file)){
    //对模板变量进行赋值
    $output = self::$output_value;
    //页头
    $output['html_title'] = $output['html_title']!='' ? $output['html_title'] :$GLOBALS['setting_config']['site_name'];
    $output['seo_keywords'] = $output['seo_keywords']!='' ? $output['seo_keywords'] :$GLOBALS['setting_config']['site_name'];
    $output['seo_description'] = $output['seo_description']!='' ? $output['seo_description'] :$GLOBALS['setting_config']['site_name'];
    $output['ref_url'] = getReferer(); Language::read('common');
    $lang = Language::getLangContent(); @header("Content-type: text/html; charset=".CHARSET);
    //判断是否使用布局方式输出模板,如果是,那么包含布局文件,并且在布局文件中包含模板文件
    if ($layout != ''){
    if (file_exists($layout_file)){
    include_once($layout_file);
    }else {
    $error = 'Tpl ERROR:'.'templates'.DS.$layout.' is not exists';
    throw_exception($error);
    }
    }else {
    include_once($tpl_file);
    }
    }else {
    $error = 'Tpl ERROR:'.'templates'.DS.$tpl_dir.$page_name.'.php'.' is not exists';
    throw_exception($error);
    }
    }
    /**
     * 显示页面Trace信息
     *
     * @return array
     */
        public static function showTrace(){
         $trace = array();
         //当前页面
    $trace[Language::get('nc_debug_current_page')] =  $_SERVER['REQUEST_URI'].'<br>';
         //请求时间
            $trace[Language::get('nc_debug_request_time')] =  date('Y-m-d H:i:s',$_SERVER['REQUEST_TIME']).'<br>';
            //系统运行时间
            $query_time = number_format((microtime(true)-StartTime),3).'s';
            $trace[Language::get('nc_debug_execution_time')] = $query_time.'<br>';
    //内存
    $trace[Language::get('nc_debug_memory_consumption')] = number_format(memory_get_usage()/1024/1024,2).'MB'.'<br>';
    //请求方法
            $trace[Language::get('nc_debug_request_method')] = $_SERVER['REQUEST_METHOD'].'<br>';
            //通信协议
            $trace[Language::get('nc_debug_communication_protocol')] = $_SERVER['SERVER_PROTOCOL'].'<br>';
            //用户代理
            $trace[Language::get('nc_debug_user_agent')] = $_SERVER['HTTP_USER_AGENT'].'<br>';
            //会话ID
            $trace[Language::get('nc_debug_session_id')] = session_id().'<br>';
            //执行日志
            $log    =   Log::read();
            $trace[Language::get('nc_debug_logging')]  = count($log)?count($log).Language::get('nc_debug_logging_1').'<br/>'.implode('<br/>',$log):Language::get('nc_debug_logging_2');
            $trace[Language::get('nc_debug_logging')] = $trace[Language::get('nc_debug_logging')].'<br>';
            //文件加载
    $files =  get_included_files();
    $trace[Language::get('nc_debug_load_files')] = count($files).str_replace("\n",'<br/>',substr(substr(print_r($files,true),7),0,-2)).'<br>';
            return $trace;
        }
    }
      

  9.   

    我的疑惑是这样的,上述获取导航栏目的方法,至始至终也没有和数据库有联系啊,但是别忘了,导航都是写在数据库中的啊,我就是这里搞不明白。为啥它不通过sql语句等手段从数据库里取值,而是通过上面那些类的方法就能搞定呢
      

  10.   

    可以查看 
    function H的
    $list = Model('cache')->call($key);
    Model('cache') 里面看看有没有调用db的语句。