Maison >développement back-end >tutoriel php >[李景山php]thinkphp核心源码注释|functionsphp

[李景山php]thinkphp核心源码注释|functionsphp

WBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWB
WBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBoriginal
2016-07-28 08:25:53952parcourir

<code><span><?php </span><span>// +----------------------------------------------------------------------</span><span>// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]</span><span>// +----------------------------------------------------------------------</span><span>// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.</span><span>// +----------------------------------------------------------------------</span><span>// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )</span><span>// +----------------------------------------------------------------------</span><span>// | Author: liu21st <liu21st></liu21st></span><span>// +----------------------------------------------------------------------</span><span>/**
 * Think 系统函数库
 */</span><span>// 同学们,上节课,我们已经 完成了 thinkphp 各种预定义变量的 定义</span><span>// 重点可以分成以下几点:</span><span>// 第一:对于 需要 web 加载的 也就是项目文档 thinkphp 采取的 dirname 的方式进行的组合跟加载</span><span>// 其特点是 ////// 这样的斜杠</span><span>// 对于 需要引入的文件 也就是 thinkphp 核心框架部分 其加载方式 采取了 __DIR__的方式进行加载</span><span>// 其特点是 \\\\ 这样的反斜杠</span><span>// ps 当然这些都是基于 window 下的方向, 也就分成了 两个 路径的 始祖 app_PATH  跟 think_PATH</span><span>// 第二:我们可以进行记录的事情是</span><span>// 作为一个框架程序,需要有能力记录 该脚本执行的 时间 跟 内存的消耗,所以 就毫不犹豫的开启了 mirctime 跟 memory_get_usage</span><span>// 此刻作为 时间 跟 内存的起点。</span><span>// 第三:值得我们注意的地方是:</span><span>// 使用了 const 跟 define 定义了 系统常量,但是 感觉就是,必须一成不变的,用了 const</span><span>// 就代表这个,彻底就固化死了,define 是可以让用户 在创建 自己的 app 中 进行修改的。 在系统进行定义之前,会判读是否定义,</span><span>// const 是没有 办法重新定义的</span><span>// 总结 基本没什么区别,这两个, 唯一就是用法啊,编译上的一个区别!</span><span>// 第四:对 系统预定义变量[GPC] 跟 文本 数据流</span><span>// 基本上可以说是进行 非转义处理 么有 addsalshe 之类的</span><span>// 第五:判读了 php 跟 web服务器 的 通信方式 cgi</span><span>// 判读了操作系统</span><span>// 判读 了 是否 脱离服务器运行 的命令行工具</span><span>// 第六: 针对于 ROOT 跟 _FILE_ 文件的定义 不统一,重新进行了多平台定义,增强了平台的可以移植性。</span><span>// 总之:就是 规范了定义 以及其 跨平台特性!</span><span>// 接下来我们讲针对与 functions.php 这些 公共函数 为大家进行讲解 20151205</span><span>/**
 * 实例化多层控制器 格式:[资源://][模块/]控制器
 *<span> @param</span> string $name 资源地址
 *<span> @param</span> string $layer 控制层名称
 *<span> @param</span> integer $level 控制器层次
 *<span> @return</span> Think\Controller|false
 */</span><span>// 此函数 进行 多层控制器实例化 功能 方便其内部调用,在写 app 应用的时候比较少用。</span><span><span>function</span><span>A</span><span>(<span>$name</span>,<span>$layer</span>=<span>''</span>,<span>$level</span>=<span>0</span>)</span> {</span><span>static</span><span>$_action</span> = <span>array</span>();<span>// 此处定义静态化 存储数组 为其实现 单列实例化模式</span><span>$layer</span>  =   <span>$layer</span>? : C(<span>'DEFAULT_C_LAYER'</span>); <span>//'DEFAULT_C_LAYER'       =>  'Controller', // 默认的控制器层名称</span><span>$level</span>  =   <span>$level</span>? : (<span>$layer</span> == C(<span>'DEFAULT_C_LAYER'</span>)?C(<span>'CONTROLLER_LEVEL'</span>):<span>1</span>); <span>//    'CONTROLLER_LEVEL'      =>  1,</span><span>if</span>(<span>isset</span>(<span>$_action</span>[<span>$name</span>.<span>$layer</span>]))<span>// 根据传入的控制器 以及其对应的层级 默认:Controller 1 层级 返回</span><span>return</span><span>$_action</span>[<span>$name</span>.<span>$layer</span>];

    <span>$class</span>  =   parse_res_name(<span>$name</span>,<span>$layer</span>,<span>$level</span>); <span>// 根据其传入的控制器 名称 层级 类名 获取对应的 class 名称</span><span>if</span>(class_exists(<span>$class</span>)) { <span>// 如果说 根据上述的生成 class 名称 如果存在 就进行实例化</span><span>$action</span>             =   <span>new</span><span>$class</span>(); <span>// 实例化</span><span>$_action</span>[<span>$name</span>.<span>$layer</span>]     =   <span>$action</span>;<span>// 存放 实例化对象到静态数组中</span><span>return</span><span>$action</span>;<span>// 返回实例化 情况</span>
    }<span>else</span> {
        <span>return</span><span>false</span>;
    }
    <span>// 例如: $name = 'admin'  结果就是 $class  = AdminController.class.php 文件 下的 AdiminController 类。</span>
}
<span>// 总结: 其实这个,就是根据你传入的 $name 返回 不同的 实例化对象。$name 可以存在的选项为:</span><span>// A('[项目://][分组/]模块','控制器层名称')   目前感觉这个level 基本上用不到。</span><span>// 等待拯救</span><span>// 好的,同学们我们今天继续,昨天了解A函数,其实就是一个 根据不同参数去实例化不同 控制器类的 一个功能函数</span><span>// 注意 A函数中 加入了一个 把不同输入参数 转换的 对应类的名称跟位置</span><span>// 接下来我们来看一下 B 函数的功能</span><span>/**
 * 执行某个行为
 *<span> @param</span> string $name 行为名称
 *<span> @param</span> string $tag 标签名称(行为类无需传入)
 *<span> @param</span> Mixed $params 传入的参数
 *<span> @return</span> void
 */</span><span><span>function</span><span>B</span><span>(<span>$name</span>, <span>$tag</span>=<span>''</span>,&<span>$params</span>=NULL)</span> {</span><span>if</span>(<span>''</span>==<span>$tag</span>){
        <span>$name</span>   .=  <span>'Behavior'</span>;
    }
    <span>return</span> \Think\Hook::exec(<span>$name</span>,<span>$tag</span>,<span>$params</span>);
}
<span>// 从字面意义上来说,这个是个 执行某个行为的函数,</span><span>// 如果 没有对应的 标签,也就是 默认的行为就是 找到钩子函数进行执行</span><span>// 另外注意一点 就是其 $params 其实是一个 引入传值,并不是一个 普通的复制传值,这样,可以无需返回就改变了传入的参数。</span><span>// 根据其 钩子函数的 特殊情况,一般其配置在 Addons 下面</span><span>// 默认是 $name Behavior 联合</span><span>// 默认的执行函数是run</span><span>// 文件位置 "Addons\\{$name}\\{$name}Addon";</span><span>// $class   =  $name.'Behavior';</span><span>// $tag    =   'run';</span><span>// return $addon->$tag($params);</span><span>// 总结,其实B函数,就是执行插件【内部/外部】的两种,引入插件的开始位置。执行开始函数。</span><span>// return $class->run(参数);</span><span>// 下面继续我们的学习,这个C函数,是一个非常常用的函数,如果说AB我们可以一般的略过,这个就要我们仔细研究一下啦</span><span>//</span><span>/**
 * 获取和设置配置参数 支持批量定义
 *<span> @param</span> string|array $name 配置变量
 *<span> @param</span> mixed $value 配置值
 *<span> @param</span> mixed $default 默认值
 *<span> @return</span> mixed
 */</span><span><span>function</span><span>C</span><span>(<span>$name</span>=null, <span>$value</span>=null,<span>$default</span>=null)</span> {</span><span>// 定义 初始化容器 ,仅能一次初始化的</span><span>static</span><span>$_config</span> = <span>array</span>();<span>// 经典的静态全局变量注册,执行单一流程时有效,其实,对于多页面不同加载的话,效果不明显。是一个可以优化的地方。</span><span>// 无参数时获取所有  情况1</span><span>if</span> (<span>empty</span>(<span>$name</span>)) { <span>// 这个是一个大招,也就是,当调用 C()的时候,注意,内部为空的时候, 就把你全家的都返回出去了。</span><span>return</span><span>$_config</span>;
    }
    <span>// 优先执行设置获取或赋值 情况 2</span><span>if</span> (is_string(<span>$name</span>)) {  <span>// 如果 是个字符串,也不下面数组的形式</span><span>if</span> (!strpos(<span>$name</span>, <span>'.'</span>)) { <span>// 此处可以记作 2.1 如果 没有 连接符号,这个我觉得有点多次一举了,但是 是为了兼容数组的保存形式。老刘啊,你真的不容易啊。</span><span>$name</span> = strtoupper(<span>$name</span>); <span>// 不关什么 字母,统统大写,这个其实是兼容的一个好的处理方式,同学们可以借鉴哦!</span><span>if</span> (is_null(<span>$value</span>)) <span>// 这里其实 是可以分的 此处记作2.1.1</span><span>return</span><span>isset</span>(<span>$_config</span>[<span>$name</span>]) ? <span>$_config</span>[<span>$name</span>] : <span>$default</span>; <span>// 此处的三元,真的很高明, 可以分成 2.1.1.1 跟 2.1.1.2</span><span>$_config</span>[<span>$name</span>] = <span>$value</span>; <span>// 此处记作 2.1.2 你懂了吗</span><span>return</span><span>null</span>; <span>//这些是各种中条件细分</span><span>// 总结就是 C('name','zhangsan'); 就是赋值 name 为张三</span><span>// 如果 $name = C('name') 就是读取 name的赋值,如果刚刚执行过上面的语句的话</span><span>// 那么 $name 就是 张三了</span>
        }
        <span>// 二维数组设置和获取支持</span><span>$name</span> = explode(<span>'.'</span>, <span>$name</span>); <span>// 这里仅仅是添加了 二维数组的支持 这里有个问题,就是 二维数组的 子元素没有变成大写</span><span>$name</span>[<span>0</span>]   =  strtoupper(<span>$name</span>[<span>0</span>]);
        <span>if</span> (is_null(<span>$value</span>))
            <span>return</span><span>isset</span>(<span>$_config</span>[<span>$name</span>[<span>0</span>]][<span>$name</span>[<span>1</span>]]) ? <span>$_config</span>[<span>$name</span>[<span>0</span>]][<span>$name</span>[<span>1</span>]] : <span>$default</span>;
        <span>$_config</span>[<span>$name</span>[<span>0</span>]][<span>$name</span>[<span>1</span>]] = <span>$value</span>;
        <span>return</span><span>null</span>;
    }
    <span>// 批量设置  情况3  直接合并数据了 其实并不很常用,原因是容易搞晕,对于我这种小智商的人,就算了,不过,偶尔会用一下。</span><span>if</span> (is_array(<span>$name</span>)){
        <span>$_config</span> = array_merge(<span>$_config</span>, array_change_key_case(<span>$name</span>,CASE_UPPER));
        <span>return</span><span>null</span>;
    }
    <span>// 其它 情况</span><span>return</span><span>null</span>; <span>// 避免非法参数</span>
}
<span>// 好的,感谢同学们,我们下节课继续!</span><span>// 其实上节课程中我们讲到C函数,这里有一思路,就函数尽量不要收到配置文件的限制,</span><span>// 我们今天继续D函数,这个函数在 thinkphp的使用中,是贯穿始终的。</span><span>// 这个是一个 实例化 Model 类的 函数</span><span>/**
 * 实例化模型类 格式 [资源://][模块/]模型
 *<span> @param</span> string $name 资源地址
 *<span> @param</span> string $layer 模型层名称
 *<span> @return</span> Think\Model
 */</span><span><span>function</span><span>D</span><span>(<span>$name</span>=<span>''</span>,<span>$layer</span>=<span>''</span>)</span> {</span><span>if</span>(<span>empty</span>(<span>$name</span>)) <span>return</span><span>new</span> Think\Model; <span>// 如果输入参数为空,直接返回默认的 Model</span><span>static</span><span>$_model</span>  =   <span>array</span>();    <span>// 否则就可以建立 静态 实例化仓库</span><span>$layer</span>          =   <span>$layer</span>? : C(<span>'DEFAULT_M_LAYER'</span>); <span>// 这里进行默认层的确认,就是</span><span>if</span>(<span>isset</span>(<span>$_model</span>[<span>$name</span>.<span>$layer</span>]))    <span>// 同样的道理 存在就返回,其实就是单列的应用思想</span><span>return</span><span>$_model</span>[<span>$name</span>.<span>$layer</span>];
    <span>$class</span>          =   parse_res_name(<span>$name</span>,<span>$layer</span>); <span>//通过解析 获取到对应的 类名 这个函数 是包含导入文件功能的,牛叉吧</span><span>if</span>(class_exists(<span>$class</span>)) {  <span>// 如果存在 就直接加载 并且实例化</span><span>$model</span>      =   <span>new</span><span>$class</span>(basename(<span>$name</span>));
    }<span>elseif</span>(<span>false</span> === strpos(<span>$name</span>,<span>'/'</span>)){ <span>// 如果说没有找到类文件 也就是没有找到类</span><span>// 自动加载公共模块下面的模型</span><span>if</span>(!C(<span>'APP_USE_NAMESPACE'</span>)){ <span>// 就去 公共模型下面寻找, 如果没有指定公共模型</span>
            import(<span>'Common/'</span>.<span>$layer</span>.<span>'/'</span>.<span>$class</span>); <span>// 默认公共模型存放位置</span>
        }<span>else</span>{
            <span>$class</span>      =   <span>'\\Common\\'</span>.<span>$layer</span>.<span>'\\'</span>.<span>$name</span>.<span>$layer</span>;<span>// 实在不行就去实例化 默认的类了</span>
        }
        <span>$model</span>      =   class_exists(<span>$class</span>)? <span>new</span><span>$class</span>(<span>$name</span>) : <span>new</span> Think\Model(<span>$name</span>);
    }<span>else</span> { <span>// 否则的日志记录错误 实例化一个基础的类 给 返回回去</span>
        Think\Log::record(<span>'D方法实例化没找到模型类'</span>.<span>$class</span>,Think\Log::NOTICE);
        <span>$model</span>      =   <span>new</span> Think\Model(basename(<span>$name</span>));
    }
    <span>$_model</span>[<span>$name</span>.<span>$layer</span>]  =  <span>$model</span>; <span>// 存入历史记录</span><span>return</span><span>$model</span>;<span>// 返回当期实例化的类  3中方式进行的实例化</span>
}
<span>// 抛出异常 基本上就是个封装了 直接转的  但是在他的核心代码里面 也没什么东西了。</span><span>// 仅仅是 继承了 php 默认的异常类</span><span>/**
 * 抛出异常处理
 *<span> @param</span> string $msg 异常消息
 *<span> @param</span> integer $code 异常代码 默认为0
 *<span> @throws</span> Think\Exception
 *<span> @return</span> void
 */</span><span><span>function</span><span>E</span><span>(<span>$msg</span>, <span>$code</span>=<span>0</span>)</span> {</span><span>throw</span><span>new</span> Think\<span>Exception</span>(<span>$msg</span>, <span>$code</span>);
}
<span>//  这个是一通过文件进行快速 数据 保存跟读取操作的事情。</span><span>/**
 * 快速文件数据读取和保存 针对简单类型数据 字符串、数组
 *<span> @param</span> string $name 缓存名称
 *<span> @param</span> mixed $value 缓存值
 *<span> @param</span> string $path 缓存路径
 *<span> @return</span> mixed
 */</span><span><span>function</span><span>F</span><span>(<span>$name</span>, <span>$value</span>=<span>''</span>, <span>$path</span>=DATA_PATH)</span> {</span><span>static</span><span>$_cache</span>  =   <span>array</span>(); <span>// 老一套啊,看起来用的很顺手啊,</span><span>$filename</span>       =   <span>$path</span> . <span>$name</span> . <span>'.php'</span>; <span>// 文件目录,也很简单。 直接使用的php 文件</span><span>if</span> (<span>''</span> !== <span>$value</span>) { <span>// 如果有数值</span><span>if</span> (is_null(<span>$value</span>)) { <span>// 如果存在的数值为空的话</span><span>// 删除缓存</span><span>if</span>(<span>false</span> !== strpos(<span>$name</span>,<span>'*'</span>)){ <span>// 如果保存的对象中中存在 * 号,错误</span><span>return</span><span>false</span>; <span>// TODO</span>
            }<span>else</span>{
                <span>unset</span>(<span>$_cache</span>[<span>$name</span>]);<span>// 删除数据缓存</span><span>return</span> Think\Storage::unlink(<span>$filename</span>,<span>'F'</span>); <span>// 删除数据文件</span>
            }
        } <span>else</span> {
            Think\Storage::put(<span>$filename</span>,serialize(<span>$value</span>),<span>'F'</span>); <span>// 用序列化的方式 写入文件</span><span>// 缓存数据</span><span>$_cache</span>[<span>$name</span>]  =   <span>$value</span>; <span>// 并且写入缓存</span><span>return</span><span>null</span>;
        }
    }
    <span>// 获取缓存数据</span><span>if</span> (<span>isset</span>(<span>$_cache</span>[<span>$name</span>])) <span>// 跟其 通用 C 很像啊 ,</span><span>return</span><span>$_cache</span>[<span>$name</span>];
    <span>if</span> (Think\Storage::has(<span>$filename</span>,<span>'F'</span>)){ <span>// 读取 存在的文件</span><span>$value</span>      =   unserialize(Think\Storage::read(<span>$filename</span>,<span>'F'</span>));
        <span>$_cache</span>[<span>$name</span>]  =   <span>$value</span>; <span>// 返回数据</span>
    } <span>else</span> {
        <span>$value</span>          =   <span>false</span>;
    }
    <span>return</span><span>$value</span>; <span>//返回数据</span>
}
<span>// 就是一个缓存数据的读取,跟 file 相比 差得多了</span><span>// 好的, 各位同学,继续</span><span>// 这里给大家提示一点,框架中的 叫做 functions.php 应用中的叫做 function.php</span><span>// 大家 明白我此刻说的应用里面的位置吗?</span><span>// 如果作为一个函数的注释来说,该函简洁明了</span><span>/**
 * 记录和统计时间(微秒)和内存使用情况
 * 使用方法:
 * <code>
 * G('begin'); // 记录开始标记位
 * // ... 区间运行代码
 * G('end'); // 记录结束标签位
 * echo G('begin','end',6); // 统计区间运行时间 精确到小数后6位  时间 用数字
 * echo G('begin','end','m'); // 统计区间内存使用情况  内存用m表示
 * 如果end标记位没有定义,则会自动以当前作为标记位
 * 其中统计内存使用需要 MEMORY_LIMIT_ON 常量为true才有效
 * </code>
 *<span> @param</span> string $start 开始标签
 *<span> @param</span> string $end 结束标签
 *<span> @param</span> integer|string $dec 小数位或者m
 *<span> @return</span> mixed
 */</span><span>// 这里不得不说 thinkphp 的创始人,特别喜欢干的一个事情,就是,根据输入参数的不同实现不同的意义</span><span>// 如 C 函数 F 函数,都是 ,如果仅仅输入 单一参数 表示读取数字, 2 个参数表示 设定数值,3 个参数一般多加了默认值</span><span>// number_format — 以千位分隔符方式格式化一个数字</span><span>// $nombre_format_francais = number_format($number, 2, ',', ' ');</span><span><span>function</span><span>G</span><span>(<span>$start</span>,<span>$end</span>=<span>''</span>,<span>$dec</span>=<span>4</span>)</span> {</span><span>static</span><span>$_info</span>       =   <span>array</span>(); <span>// 这个是时间仓库</span><span>static</span><span>$_mem</span>        =   <span>array</span>(); <span>// 这个是内存仓库</span><span>if</span>(is_float(<span>$end</span>)) { <span>// 记录时间  如果传值如此 G('start',2342353234.453); 就是个记录 跟上面的风格保持一致</span><span>// 有 小数 传入 就是 结束</span><span>$_info</span>[<span>$start</span>]  =   <span>$end</span>; <span>// 或者 如果传值如此 G('start',microtime(TRUE));</span>
    }<span>elseif</span>(!<span>empty</span>(<span>$end</span>)){ <span>// 统计时间和内存使用  也就是其默认的优先级 是 时间</span><span>// 有 非数字 结尾 就是 返回 差值</span><span>if</span>(!<span>isset</span>(<span>$_info</span>[<span>$end</span>])) <span>$_info</span>[<span>$end</span>]       =  microtime(<span>TRUE</span>);
        <span>if</span>(MEMORY_LIMIT_ON && <span>$dec</span>==<span>'m'</span>){ <span>// 如果开启了内存记录 并且明确是内存的记录</span><span>if</span>(!<span>isset</span>(<span>$_mem</span>[<span>$end</span>])) <span>$_mem</span>[<span>$end</span>]     =  memory_get_usage(); <span>// 获取内存记录</span><span>return</span> number_format((<span>$_mem</span>[<span>$end</span>]-<span>$_mem</span>[<span>$start</span>])/<span>1024</span>); <span>// 获取返回的格式化数值</span>
        }<span>else</span>{
            <span>return</span> number_format((<span>$_info</span>[<span>$end</span>]-<span>$_info</span>[<span>$start</span>]),<span>$dec</span>); <span>// 返回格式化的位数 默认4位小数</span>
        }

    }<span>else</span>{ <span>// 记录时间和内存使用</span><span>// 单独的话,就是同步记录 内存 跟时间的 标志位。</span><span>$_info</span>[<span>$start</span>]  =  microtime(<span>TRUE</span>);
        <span>if</span>(MEMORY_LIMIT_ON) <span>$_mem</span>[<span>$start</span>]           =  memory_get_usage();
    }
    <span>return</span><span>null</span>;
}
<span>// 无 H 函数</span><span>// 今日上午面试,就到这里了,感谢!</span><span>//  嗯,昨天有点匆忙,其实这个G就是一个记录时间 跟内存的函数,都过第二,第三个参数的属性</span><span>//  进行区分 是记录的时间还是 其它什么的 ,但是不管怎么得瑟,都是 同时记录的时间 给内存</span><span>//  通过时间跟内存的记录可以 从一个角度来反映出php 程序运行的性能</span><span>// 接下来是我们强大的I输入过滤函数,支持默认值</span><span>/**
 * 获取输入参数 支持过滤和默认值
 * 使用方法:
 * <code>
 * I('id',0); 获取id参数 自动判断get或者post // 嗯,你举例的这几个,确实很常用
 * I('post.name','','htmlspecialchars'); 获取$_POST['name']
 * I('get.'); 获取$_GET
 * </code>
 *<span> @param</span> string $name 变量的名称 支持指定类型
 *<span> @param</span> mixed $default 不存在的时候默认值
 *<span> @param</span> mixed $filter 参数过滤方法
 *<span> @param</span> mixed $datas 要获取的额外数据源
 *<span> @return</span> mixed
 */</span><span><span>function</span><span>I</span><span>(<span>$name</span>,<span>$default</span>=<span>''</span>,<span>$filter</span>=null,<span>$datas</span>=null)</span> {</span><span>// 第一步:指定仓库</span><span>static</span><span>$_PUT</span>   =   <span>null</span>;  <span>// 默认单数据仓库</span><span>// 第二步:判定输入类型</span><span>if</span>(strpos(<span>$name</span>,<span>'/'</span>)){ <span>// 指定修饰符</span><span>list</span>(<span>$name</span>,<span>$type</span>)    =   explode(<span>'/'</span>,<span>$name</span>,<span>2</span>);
    }<span>elseif</span>(C(<span>'VAR_AUTO_STRING'</span>)){ <span>// 默认强制转换为字符串</span><span>// // 输入变量是否自动强制转换为字符串 如果开启则数组变量需要手动传入变量修饰符获取变量</span><span>// 其实上面的 这个默认是false</span><span>$type</span>   =   <span>'s'</span>;
    }
    <span>// 第三步:数据源获取</span><span>// 第三步:第一小步骤:就是分解数据源</span><span>// 在一般的程序中,上面这两个是用不到的,也就是 指定 数据类型, 默认都没有指定。</span><span>if</span>(strpos(<span>$name</span>,<span>'.'</span>)) { <span>// 指定参数来源</span><span>list</span>(<span>$method</span>,<span>$name</span>) =   explode(<span>'.'</span>,<span>$name</span>,<span>2</span>);
    }<span>else</span>{ <span>// 默认为自动判断</span><span>$method</span> =   <span>'param'</span>;
    }
    <span>// 第三步:第二小步骤:关联数据源</span><span>// 指定数据源,常用的就是 get post 了</span><span>switch</span>(strtolower(<span>$method</span>)) { <span>// 其实这个用的很经典 比较之前 先 小写</span><span>case</span><span>'get'</span>     :
            <span>$input</span> =& <span>$_GET</span>; <span>// 取地址 用的也不错,很有想法</span><span>break</span>;
        <span>case</span><span>'post'</span>    :
            <span>$input</span> =& <span>$_POST</span>;
            <span>break</span>;
        <span>case</span><span>'put'</span>     :
            <span>if</span>(is_null(<span>$_PUT</span>)){
                parse_str(file_get_contents(<span>'php://input'</span>), <span>$_PUT</span>);
            }
            <span>$input</span> 	=	<span>$_PUT</span>;
<span>/*
读取POST数据
不能用于multipart/form-data类型
php://input VS $HTTP_RAW_POST_DATA
读取POST数据 */</span><span>break</span>;
        <span>case</span><span>'param'</span>   :<span>// 其实这个最不科学了,为了兼容懒人编程,</span><span>switch</span>(<span>$_SERVER</span>[<span>'REQUEST_METHOD'</span>]) {
                <span>case</span><span>'POST'</span>:
                    <span>$input</span>  =  <span>$_POST</span>;
                    <span>break</span>;
                <span>case</span><span>'PUT'</span>:
                    <span>if</span>(is_null(<span>$_PUT</span>)){
                        parse_str(file_get_contents(<span>'php://input'</span>), <span>$_PUT</span>);
                    }
                    <span>$input</span> 	=	<span>$_PUT</span>;
                    <span>break</span>;
                <span>default</span>:
                    <span>$input</span>  =  <span>$_GET</span>;
            }
            <span>break</span>;
        <span>// 常用的三种输入 获取方式 GET POST PUT</span><span>case</span><span>'path'</span>    : <span>// 居然还有路径获取,我调用中从来没用过</span><span>$input</span>  =   <span>array</span>();
            <span>if</span>(!<span>empty</span>(<span>$_SERVER</span>[<span>'PATH_INFO'</span>])){
                <span>$depr</span>   =   C(<span>'URL_PATHINFO_DEPR'</span>);<span>// 路径分隔符</span><span>//'URL_PATHINFO_DEPR'     =>  '/',  // PATHINFO模式下,各参数之间的分割符号</span><span>$input</span>  =   explode(<span>$depr</span>,trim(<span>$_SERVER</span>[<span>'PATH_INFO'</span>],<span>$depr</span>));
            }
            <span>break</span>;
        <span>case</span><span>'request'</span> :
            <span>$input</span> =& <span>$_REQUEST</span>;
            <span>break</span>;
        <span>case</span><span>'session'</span> :
            <span>$input</span> =& <span>$_SESSION</span>;
            <span>break</span>;
        <span>case</span><span>'cookie'</span>  :
            <span>$input</span> =& <span>$_COOKIE</span>;
            <span>break</span>;
        <span>case</span><span>'server'</span>  :
            <span>$input</span> =& <span>$_SERVER</span>;
            <span>break</span>;
        <span>case</span><span>'globals'</span> :
            <span>$input</span> =& <span>$GLOBALS</span>;
            <span>break</span>;
        <span>case</span><span>'data'</span>    :
            <span>$input</span> =& <span>$datas</span>;
            <span>break</span>;
        <span>default</span>:
            <span>return</span><span>null</span>;
    }
    <span>// 第四步:明确获取变量</span><span>// 4.1 获取全部数值</span><span>if</span>(<span>''</span>==<span>$name</span>) { <span>// 获取全部变量</span><span>$data</span>       =   <span>$input</span>;
        <span>// 用过滤函数继续过滤</span><span>$filters</span>    =   <span>isset</span>(<span>$filter</span>)?<span>$filter</span>:C(<span>'DEFAULT_FILTER'</span>);
        <span>if</span>(<span>$filters</span>) {
            <span>if</span>(is_string(<span>$filters</span>)){
                <span>$filters</span>    =   explode(<span>','</span>,<span>$filters</span>);
            }
            <span>foreach</span>(<span>$filters</span><span>as</span><span>$filter</span>){
                <span>$data</span>   =   array_map_recursive(<span>$filter</span>,<span>$data</span>); <span>// 参数过滤</span>
            }
        }
        <span>// 4.2  获取 指定数值</span>
    }<span>elseif</span>(<span>isset</span>(<span>$input</span>[<span>$name</span>])) { <span>// 取值操作 如果明确一个 取值</span><span>$data</span>       =   <span>$input</span>[<span>$name</span>]; <span>// 数据获取完成</span><span>// 开始执行过滤</span><span>$filters</span>    =   <span>isset</span>(<span>$filter</span>)?<span>$filter</span>:C(<span>'DEFAULT_FILTER'</span>);
        <span>// 存在过滤器 开始过滤</span><span>if</span>(<span>$filters</span>) {
            <span>if</span>(is_string(<span>$filters</span>)){
                <span>if</span>(<span>0</span> === strpos(<span>$filters</span>,<span>'/'</span>)){
                    <span>if</span>(<span>1</span> !== preg_match(<span>$filters</span>,(string)<span>$data</span>)){ <span>// 过滤器支持正则</span><span>// 支持正则验证</span><span>return</span><span>isset</span>(<span>$default</span>) ? <span>$default</span> : <span>null</span>;
                    }
                }<span>else</span>{
                    <span>$filters</span>    =   explode(<span>','</span>,<span>$filters</span>);
                }
            }<span>elseif</span>(is_int(<span>$filters</span>)){
                <span>$filters</span>    =   <span>array</span>(<span>$filters</span>);
            }
            <span>// 进行数组过滤</span><span>if</span>(is_array(<span>$filters</span>)){
                <span>foreach</span>(<span>$filters</span><span>as</span><span>$filter</span>){
                    <span>if</span>(function_exists(<span>$filter</span>)) {
                        <span>$data</span>   =   is_array(<span>$data</span>) ? array_map_recursive(<span>$filter</span>,<span>$data</span>) : <span>$filter</span>(<span>$data</span>); <span>// 参数过滤</span>
                    }<span>else</span>{
                        <span>$data</span>   =   filter_var(<span>$data</span>,is_int(<span>$filter</span>) ? <span>$filter</span> : filter_id(<span>$filter</span>));
                        <span>if</span>(<span>false</span> === <span>$data</span>) {
                            <span>return</span><span>isset</span>(<span>$default</span>) ? <span>$default</span> : <span>null</span>;
                        }
                    }
                }
            }
        }
        <span>// 对输出数据类型进行指定 默认 字符串</span><span>if</span>(!<span>empty</span>(<span>$type</span>)){
            <span>switch</span>(strtolower(<span>$type</span>)){
                <span>case</span><span>'a'</span>:   <span>// 数组</span><span>$data</span> 	=	(<span>array</span>)<span>$data</span>;
                    <span>break</span>;
                <span>case</span><span>'d'</span>:   <span>// 数字</span><span>$data</span> 	=	(int)<span>$data</span>;
                    <span>break</span>;
                <span>case</span><span>'f'</span>:   <span>// 浮点</span><span>$data</span> 	=	(float)<span>$data</span>;
                    <span>break</span>;
                <span>case</span><span>'b'</span>:   <span>// 布尔</span><span>$data</span> 	=	(boolean)<span>$data</span>;
                    <span>break</span>;
                <span>case</span><span>'s'</span>:   <span>// 字符串</span><span>default</span>:
                    <span>$data</span>   =   (string)<span>$data</span>;
            }
        }
        <span>//4.3 获取 默认的 数值了</span>
    }<span>else</span>{ <span>// 变量默认值</span><span>$data</span>       =    <span>isset</span>(<span>$default</span>)?<span>$default</span>:<span>null</span>;
    }
    <span>// 最后在返回数据之前,在进行处理了,就是 如果是数组,就 执行 默认的过滤函数</span>
    is_array(<span>$data</span>) && array_walk_recursive(<span>$data</span>,<span>'think_filter'</span>);
    <span>return</span><span>$data</span>;
}
<span>// 总结,其实经过上述函数的分析大致可以这样学习的地方:</span><span>// 第一:按步骤进行分支 代码书写 类似于 第一步: 1.1 1.2 第二步: 2.1 2.2 这样</span><span>// 第二:依然贯穿了其传统,通过 参数 调整其输出的特色 就是各种参数的样式进行不同的兼容</span><span>// 第三:就是 各种过滤函数的方便 搭配。真心不错!</span><span>// 我看好你哦,哈哈!</span><span>// 无 J函数</span><span>// 无 K函数</span><span>// 遇到 这个 L 函数 一般情况下就是 做的 语言配置。</span><span>/**
 * 获取和设置语言定义(不区分大小写)
 *<span> @param</span> string|array $name 语言变量
 *<span> @param</span> mixed $value 语言值或者变量
 *<span> @return</span> mixed
 */</span><span><span>function</span><span>L</span><span>(<span>$name</span>=null, <span>$value</span>=null)</span> {</span><span>static</span><span>$_lang</span> = <span>array</span>();<span>// 老步调,定义仓库</span><span>// 空参数返回所有定义</span><span>// 三种方式</span><span>// 第一种方式:为空</span><span>if</span> (<span>empty</span>(<span>$name</span>)) <span>// 老步调: 无输入 返回全部</span><span>return</span><span>$_lang</span>;
    <span>// 判断语言获取(或设置)</span><span>// 若不存在,直接返回全大写$name</span><span>// 如果 字符串</span><span>// 第二种方式:字符串  然后在细分  空 数组 默认 记住这里的return 其实是个神器</span><span>if</span> (is_string(<span>$name</span>)) { <span>// 如果是字符串</span><span>$name</span>   =   strtoupper(<span>$name</span>); <span>// 第一步:统统转换成为大写</span><span>if</span> (is_null(<span>$value</span>)){ <span>// 判读 是 设置 还是读取</span><span>return</span><span>isset</span>(<span>$_lang</span>[<span>$name</span>]) ? <span>$_lang</span>[<span>$name</span>] : <span>$name</span>; <span>// 有定义返回定义,没有定义,直接返回</span>
        }<span>elseif</span>(is_array(<span>$value</span>)){ <span>// 如果是数组</span><span>// 支持变量</span><span>$replace</span> = array_keys(<span>$value</span>); <span>//返回包含数组中所有键名的一个新数组:</span><span>foreach</span>(<span>$replace</span><span>as</span> &<span>$v</span>){ <span>// 好复杂,这一节没看懂,嘿嘿 能看懂的在楼下回复哈!感谢</span><span>$v</span> = <span>'{$'</span>.<span>$v</span>.<span>'}'</span>;
            }
            <span>return</span> str_replace(<span>$replace</span>,<span>$value</span>,<span>isset</span>(<span>$_lang</span>[<span>$name</span>]) ? <span>$_lang</span>[<span>$name</span>] : <span>$name</span>);
        }
        <span>$_lang</span>[<span>$name</span>] = <span>$value</span>; <span>// 语言定义  否则就进行定义</span><span>return</span><span>null</span>;
    }
    <span>// 批量定义</span><span>// 第三种方式:数组</span><span>if</span> (is_array(<span>$name</span>)) <span>// 批量 定义 array_change_key_case() 函数将数组的所有的键都转换为大写字母或小写字母。默认大写</span><span>$_lang</span> = array_merge(<span>$_lang</span>, array_change_key_case(<span>$name</span>, CASE_UPPER));
    <span>return</span><span>null</span>;
}
<span>// 特别常用的 一款 函数 不过 我稍后会  推荐D函数  但是任何函数,都有自己的 特点</span><span>/**
 * 实例化一个没有模型文件的Model
 *<span> @param</span> string $name Model名称 支持指定基础模型 例如 MongoModel:User
 *<span> @param</span> string $tablePrefix 表前缀
 *<span> @param</span> mixed $connection 数据库连接信息
 *<span> @return</span> Think\Model
 */</span><span>//</span><span><span>function</span><span>M</span><span>(<span>$name</span>=<span>''</span>, <span>$tablePrefix</span>=<span>''</span>,<span>$connection</span>=<span>''</span>)</span> {</span><span>static</span><span>$_model</span>  = <span>array</span>();<span>// 一成不变的仓库</span><span>if</span>(strpos(<span>$name</span>,<span>':'</span>)) { <span>// 可以组合其 代码 然后 拼接成为 类,跟 类名</span><span>list</span>(<span>$class</span>,<span>$name</span>)    =  explode(<span>':'</span>,<span>$name</span>);
    }<span>else</span>{
        <span>$class</span>      =   <span>'Think\\Model'</span>; <span>// 否则的话,执行 默认的 Model 类 实例化</span>
    }
    <span>// 这个相当于做了一个唯一值</span><span>$guid</span>           =   (is_array(<span>$connection</span>)?implode(<span>''</span>,<span>$connection</span>):<span>$connection</span>).<span>$tablePrefix</span> . <span>$name</span> . <span>'_'</span> . <span>$class</span>;
    <span>if</span> (!<span>isset</span>(<span>$_model</span>[<span>$guid</span>])) <span>// 单列  单列</span><span>$_model</span>[<span>$guid</span>] = <span>new</span><span>$class</span>(<span>$name</span>,<span>$tablePrefix</span>,<span>$connection</span>); <span>// 实例化保存后的单列</span><span>return</span><span>$_model</span>[<span>$guid</span>]; <span>// 这个不多说了,就这样了。</span>
}
<span>/**
 * 设置和获取统计数据
 * 使用方法:
 * <code>
 * N('db',1); // 记录数据库操作次数
 * N('read',1); // 记录读取次数
 * echo N('db'); // 获取当前页面数据库的所有操作次数
 * echo N('read'); // 获取当前页面读取次数
 * </code>
 *<span> @param</span> string $key 标识位置
 *<span> @param</span> integer $step 步进值
 *<span> @param</span> boolean $save 是否保存结果
 *<span> @return</span> mixed
 */</span><span><span>function</span><span>N</span><span>(<span>$key</span>, <span>$step</span>=<span>0</span>,<span>$save</span>=false)</span> {</span><span>static</span><span>$_num</span>    = <span>array</span>(); <span>// 仓库</span><span>if</span> (!<span>isset</span>(<span>$_num</span>[<span>$key</span>])) { <span>// 如果说没有设置 当前值</span><span>$_num</span>[<span>$key</span>] = (<span>false</span> !== <span>$save</span>)? S(<span>'N_'</span>.<span>$key</span>) :  <span>0</span>; <span>// 如果设置了存储 就在S 函数中,读取处理,否则就0了</span>
    }
    <span>if</span> (<span>empty</span>(<span>$step</span>)){ <span>// 如果没有步进设置</span><span>return</span><span>$_num</span>[<span>$key</span>];
    }<span>else</span>{ <span>// 否则 按照步进 的方式前进</span><span>$_num</span>[<span>$key</span>] = <span>$_num</span>[<span>$key</span>] + (int)<span>$step</span>;
    }
    <span>if</span>(<span>false</span> !== <span>$save</span>){ <span>// 保存结果  其实 这个是通过 缓存  读取 函数的。</span>
        S(<span>'N_'</span>.<span>$key</span>,<span>$_num</span>[<span>$key</span>],<span>$save</span>);
    }
    <span>return</span><span>null</span>;
}
<span>// 无 O函数</span><span>// 无 P函数</span><span>// 无 Q函数</span><span>// 今日到此结束,讲述了 L M N 函数 语言包 M 实例化 可以 指定实例化类 跟 连接的数据库 N 记录步骤</span><span>// 不好意思,糊涂了,昨天没有更新,今天也才更新</span><span>/**
 * 远程调用控制器的操作方法 URL 参数格式 [资源://][模块/]控制器/操作
 *<span> @param</span> string $url 调用地址
 *<span> @param</span> string|array $vars 调用参数 支持字符串和数组
 *<span> @param</span> string $layer 要调用的控制层名称
 *<span> @return</span> mixed
 */</span><span>// 把查询字符串解析到变量中</span><span>// parse_str() 函数把查询字符串解析到变量中。</span><span>// 注释:php.ini 文件中的 magic_quotes_gpc 设置影响该函数的输出。如果已启用,那么在 parse_str() 解析之前,变量会被 addslashes() 转换。</span><span>/**
parse_str("name=Bill&age=60");
echo $name."<br>";
echo $age;
 *
parse_str("name=Bill&age=60",$myArray);
print_r($myArray);
 */</span><span>// print_r(pathinfo("/testweb/test.txt"));</span><span>// pathinfo() 返回一个关联数组包含有 path 的信息。</span><span>/**
Array
(
[dirname] => /testweb
[basename] => test.txt
[extension] => txt
)
 * [dirname]
[basename]
[extension]
 */</span><span>/**
Class ClassA
{
function bc($b, $c) {
$bc = $b + $c;
echo $bc;
}
}
call_user_func_array(array('ClassA','bc'), array("111", "222"));
//显示 333
 */</span><span><span>function</span><span>R</span><span>(<span>$url</span>,<span>$vars</span>=array<span>()</span>,<span>$layer</span>=<span>''</span>)</span> {</span><span>$info</span>   =   pathinfo(<span>$url</span>); <span>// 解析路径</span><span>$action</span> =   <span>$info</span>[<span>'basename'</span>];  <span>// 获取文件名</span><span>$module</span> =   <span>$info</span>[<span>'dirname'</span>];   <span>// 获取 文件路径</span><span>$class</span>  =   A(<span>$module</span>,<span>$layer</span>); <span>// 获取实际 class 实例化  多了一层级的 关系  如Widget</span><span>if</span>(<span>$class</span>){ <span>// 如果存在 类</span><span>if</span>(is_string(<span>$vars</span>)) { <span>// 如果有变量 传入</span>
            parse_str(<span>$vars</span>,<span>$vars</span>); <span>// 解析传入参数到数组</span>
        }
        <span>return</span> call_user_func_array(<span>array</span>(&<span>$class</span>,<span>$action</span>.C(<span>'ACTION_SUFFIX'</span>)),<span>$vars</span>); <span>//</span>
    }<span>else</span>{
        <span>return</span><span>false</span>;
    }
}
<span>// 总结,其实 这个R 就是 一个call_user_func_array 的升级版本,通过 url 直接进行处理。</span><span>// 还有一个半小时 今天结束。继续今天的学习</span><span>// 这个函数 其实也是个很牛叉的函数 ,好像可以 用F函数,让我们对比一下吧,看看 这两个鬼有什么区别。</span><span>/**
 * 缓存管理
 *<span> @param</span> mixed $name 缓存名称,如果为数组表示进行缓存设置
 *<span> @param</span> mixed $value 缓存值
 *<span> @param</span> mixed $options 缓存参数
 *<span> @return</span> mixed
 */</span><span><span>function</span><span>S</span><span>(<span>$name</span>,<span>$value</span>=<span>''</span>,<span>$options</span>=null)</span> {</span><span>static</span><span>$cache</span>   =   <span>''</span>; <span>// 仓库 仓库 仓库 又是仓库</span><span>//第一步:初始化</span><span>if</span>(is_array(<span>$options</span>)){ <span>// 如果缓存 参数 其实有点乱 type 可以放到任何一个位置</span><span>// 缓存操作的同时初始化 其实就是 就是个 初始化 的过程</span><span>$type</span>       =   <span>isset</span>(<span>$options</span>[<span>'type'</span>])?<span>$options</span>[<span>'type'</span>]:<span>''</span>;
        <span>$cache</span>      =   Think\Cache::getInstance(<span>$type</span>,<span>$options</span>);
    }<span>elseif</span>(is_array(<span>$name</span>)) { <span>// 缓存初始化 // 如果缓存 参数 其实有点乱 type 可以放到任何一个位置</span><span>$type</span>       =   <span>isset</span>(<span>$name</span>[<span>'type'</span>])?<span>$name</span>[<span>'type'</span>]:<span>''</span>;
        <span>$cache</span>      =   Think\Cache::getInstance(<span>$type</span>,<span>$name</span>);
        <span>return</span><span>$cache</span>;
    }<span>elseif</span>(<span>empty</span>(<span>$cache</span>)) { <span>// 自动初始化 还没有的话</span><span>$cache</span>      =   Think\Cache::getInstance();  <span>//初始化</span>
    }
    <span>// 根据对数据 进行 设计</span><span>if</span>(<span>''</span>=== <span>$value</span>){ <span>// 获取缓存</span><span>return</span><span>$cache</span>->get(<span>$name</span>); <span>// 获取数据</span>
    }<span>elseif</span>(is_null(<span>$value</span>)) { <span>// 删除缓存</span><span>return</span><span>$cache</span>->rm(<span>$name</span>); <span>// 删除数据</span>
    }<span>else</span> { <span>// 缓存数据</span><span>if</span>(is_array(<span>$options</span>)) {
            <span>$expire</span>     =   <span>isset</span>(<span>$options</span>[<span>'expire'</span>])?<span>$options</span>[<span>'expire'</span>]:<span>NULL</span>;
        }<span>else</span>{
            <span>$expire</span>     =   is_numeric(<span>$options</span>)?<span>$options</span>:<span>NULL</span>;
        }
        <span>return</span><span>$cache</span>->set(<span>$name</span>, <span>$value</span>, <span>$expire</span>); <span>// 保存数据</span>
    }
}

<span>// 总结,其实这个 就是 干什么的呢,关键点是那个 class 类函数</span><span>// 其实那个 函数 也没什么了</span><span>// 今天学一个新的东西,就是 写 模版引擎</span><span>/**
 * 获取模版文件 格式 资源://模块@主题/控制器/操作
 *<span> @param</span> string $template 模版资源地址
 *<span> @param</span> string $layer 视图层(目录)名称
 *<span> @return</span> string
 */</span><span><span>function</span><span>T</span><span>(<span>$template</span>=<span>''</span>,<span>$layer</span>=<span>''</span>)</span>{</span><span>// 解析模版资源地址  第一步:</span><span>if</span>(<span>false</span> === strpos(<span>$template</span>,<span>'://'</span>)){
        <span>$template</span>   =   <span>'http://'</span>.str_replace(<span>':'</span>, <span>'/'</span>,<span>$template</span>);
    }
    <span>$info</span>   =   parse_url(<span>$template</span>); <span>// 第二步:解析到自己的 数组里面</span><span>$file</span>   =   <span>$info</span>[<span>'host'</span>].(<span>isset</span>(<span>$info</span>[<span>'path'</span>])?<span>$info</span>[<span>'path'</span>]:<span>''</span>);
    <span>$module</span> =   <span>isset</span>(<span>$info</span>[<span>'user'</span>])?<span>$info</span>[<span>'user'</span>].<span>'/'</span>:MODULE_NAME.<span>'/'</span>; <span>// 扩展用户名</span><span>$extend</span> =   <span>$info</span>[<span>'scheme'</span>]; <span>// 扩展 文件扩展名</span><span>$layer</span>  =   <span>$layer</span>?<span>$layer</span>:C(<span>'DEFAULT_V_LAYER'</span>); <span>// 层次</span><span>// 获取当前主题的模版路径</span><span>$auto</span>   =   C(<span>'AUTOLOAD_NAMESPACE'</span>);
    <span>if</span>(<span>$auto</span> && <span>isset</span>(<span>$auto</span>[<span>$extend</span>])){ <span>// 扩展资源</span><span>$baseUrl</span>    =   <span>$auto</span>[<span>$extend</span>].<span>$module</span>.<span>$layer</span>.<span>'/'</span>;
    }<span>elseif</span>(C(<span>'VIEW_PATH'</span>)){
        <span>// 改变模块视图目录</span><span>$baseUrl</span>    =   C(<span>'VIEW_PATH'</span>);
    }<span>elseif</span>(defined(<span>'TMPL_PATH'</span>)){
        <span>// 指定全局视图目录</span><span>$baseUrl</span>    =   TMPL_PATH.<span>$module</span>;
    }<span>else</span>{
        <span>$baseUrl</span>    =   APP_PATH.<span>$module</span>.<span>$layer</span>.<span>'/'</span>;
    }

    <span>// 获取主题</span><span>$theme</span>  =   substr_count(<span>$file</span>,<span>'/'</span>)2</span> ? C(<span>'DEFAULT_THEME'</span>) : <span>''</span>;

    <span>// 分析模板文件规则</span><span>$depr</span>   =   C(<span>'TMPL_FILE_DEPR'</span>);
    <span>if</span>(<span>''</span> == <span>$file</span>) {
        <span>// 如果模板文件名为空 按照默认规则定位</span><span>$file</span> = CONTROLLER_NAME . <span>$depr</span> . ACTION_NAME;
    }<span>elseif</span>(<span>false</span> === strpos(<span>$file</span>, <span>'/'</span>)){
        <span>$file</span> = CONTROLLER_NAME . <span>$depr</span> . <span>$file</span>;
    }<span>elseif</span>(<span>'/'</span> != <span>$depr</span>){
        <span>$file</span>   =   substr_count(<span>$file</span>,<span>'/'</span>)><span>1</span> ? substr_replace(<span>$file</span>,<span>$depr</span>,strrpos(<span>$file</span>,<span>'/'</span>),<span>1</span>) : str_replace(<span>'/'</span>, <span>$depr</span>, <span>$file</span>);
    }
    <span>return</span><span>$baseUrl</span>.(<span>$theme</span>?<span>$theme</span>.<span>'/'</span>:<span>''</span>).<span>$file</span>.C(<span>'TMPL_TEMPLATE_SUFFIX'</span>);
}
<span>// 总结,其实,这货 就是返回了一个 真实的网址路径而已啦</span><span>// 今天是这个新东西,组装产品</span><span>/**
 * URL组装 支持不同URL模式
 *<span> @param</span> string $url URL表达式,格式:'[模块/控制器/操作#锚点@域名]?参数1=值1&参数2=值2...'
 *<span> @param</span> string|array $vars 传入的参数,支持数组和字符串
 *<span> @param</span> string|boolean $suffix 伪静态后缀,默认为true表示获取配置值
 *<span> @param</span> boolean $domain 是否显示域名
 *<span> @return</span> string
 * 本函数不是用来验证给定 URL 的合法性的,只是将其分解为下面列出的部分。不完整的 URL 也被接受,parse_url() 会尝试尽量正确地将其解析。
 * Array
(
[scheme] => http
[host] => hostname
[user] => username
[pass] => password
[path] => /path
[query] => arg=value   在问号 ? 之后
[fragment] => anchor  在散列符号 # 之后
)
 * $url = 'http://username:password@hostname/path?arg=value#anchor';
 */</span><span><span>function</span><span>U</span><span>(<span>$url</span>=<span>''</span>,<span>$vars</span>=<span>''</span>,<span>$suffix</span>=true,<span>$domain</span>=false)</span> {</span><span>// 解析URL 其实这里传入的 url 不是 正常地址上人的 url 他重新做了组合,个人觉得不是很科学</span><span>$info</span>   =  parse_url(<span>$url</span>); <span>// 解析参数  这里的解析方式 跟正常的还不太一样</span><span>// 情况 1</span><span>//    $url = 'Home/Index/index#zhangsan@www.maizi.net?name=lisi&age=32';</span><span>//    var_dump(parse_url($url));</span><span>//array (size=2)</span><span>//'path' => string 'Home/Index/index' (length=16)</span><span>//  'fragment' => string 'zhangsan@www.maizi.net?name=lisi&age=32' (length=39)</span><span>// 情况2</span><span>//    $url = 'Home/Index/index@www.maizi.net?name=lisi&age=32';</span><span>//    var_dump(parse_url($url));</span><span>//    array (size=2)</span><span>//  'path' => string 'Home/Index/index@www.maizi.net' (length=30)</span><span>//  'query' => string 'name=lisi&age=32' (length=16)</span><span>$url</span>    =  !<span>empty</span>(<span>$info</span>[<span>'path'</span>])?<span>$info</span>[<span>'path'</span>]:ACTION_NAME; <span>// 如果解析到了路径,就用解析的路径,否则就用action_name</span><span>if</span>(<span>isset</span>(<span>$info</span>[<span>'fragment'</span>])) { <span>// 解析锚点  就是 网页中 跳转到网站固定位置的 标记</span><span>$anchor</span> =   <span>$info</span>[<span>'fragment'</span>]; <span>// 其实这种是全的  '[模块/控制器/操作#锚点@域名]?参数1=值1&参数2=值2...'</span><span>if</span>(<span>false</span> !== strpos(<span>$anchor</span>,<span>'?'</span>)) { <span>// 解析参数  如果锚点 后面还有跟随的参数</span><span>list</span>(<span>$anchor</span>,<span>$info</span>[<span>'query'</span>]) = explode(<span>'?'</span>,<span>$anchor</span>,<span>2</span>);
        }
        <span>if</span>(<span>false</span> !== strpos(<span>$anchor</span>,<span>'@'</span>)) { <span>// 解析域名  如果锚点后,还有@ 域名</span><span>list</span>(<span>$anchor</span>,<span>$host</span>)    =   explode(<span>'@'</span>,<span>$anchor</span>, <span>2</span>);
        }
    }<span>elseif</span>(<span>false</span> !== strpos(<span>$url</span>,<span>'@'</span>)) { <span>// 解析域名 把用户名密码 跟 域名拆分</span><span>list</span>(<span>$url</span>,<span>$host</span>)    =   explode(<span>'@'</span>,<span>$info</span>[<span>'path'</span>], <span>2</span>);
        <span>// '[模块/控制器/操作@域名]?参数1=值1&参数2=值2...' 这种是不全的</span>
    }
    <span>// 解析子域名  host 就是域名了</span><span>if</span>(<span>isset</span>(<span>$host</span>)) { <span>// 不是二级域名吗  其实一般情况下是没有这个东西的</span><span>// 其实这个用法 很奇怪  一般情况下,就是 $domain = $host  这里可以能是跟随参数的</span><span>$domain</span> = <span>$host</span>.(strpos(<span>$host</span>,<span>'.'</span>)?<span>''</span>:strstr(<span>$_SERVER</span>[<span>'HTTP_HOST'</span>],<span>'.'</span>));
    }<span>elseif</span>(<span>$domain</span>===<span>true</span>){ <span>//如果显示域名 如果有添加,这里就不是 true boolen类型才可以哈</span><span>$domain</span> = <span>$_SERVER</span>[<span>'HTTP_HOST'</span>]; <span>// 显示 主机名 域名</span><span>if</span>(C(<span>'APP_SUB_DOMAIN_DEPLOY'</span>) ) { <span>// 开启子域名部署  默认是没有开启</span><span>$domain</span> = <span>$domain</span>==<span>'localhost'</span>?<span>'localhost'</span>:<span>'www'</span>.strstr(<span>$_SERVER</span>[<span>'HTTP_HOST'</span>],<span>'.'</span>); <span>// 默认给他缓存了 www.你的域名啦 本地的就不管了</span><span>// '子域名'=>array('模块[/控制器]');  找到子域名的 匹配规则 实际上,可能用不到哈</span><span>foreach</span> (C(<span>'APP_SUB_DOMAIN_RULES'</span>) <span>as</span><span>$key</span> => <span>$rule</span>) {<span>// 处理 子域名规则</span><span>$rule</span>   =   is_array(<span>$rule</span>)?<span>$rule</span>[<span>0</span>]:<span>$rule</span>;
                <span>if</span>(<span>false</span> === strpos(<span>$key</span>,<span>'*'</span>) && <span>0</span>=== strpos(<span>$url</span>,<span>$rule</span>)) {
                    <span>$domain</span> = <span>$key</span>.strstr(<span>$domain</span>,<span>'.'</span>); <span>// 生成对应子域名</span><span>$url</span>    =  substr_replace(<span>$url</span>,<span>''</span>,<span>0</span>,strlen(<span>$rule</span>));
                    <span>break</span>;
                }
            }
        }
    }

    <span>// 解析参数 解析 参数,这个是 后面传入的参数</span><span>if</span>(is_string(<span>$vars</span>)) { <span>// aaa=1&bbb=2 转换成数组</span>
        parse_str(<span>$vars</span>,<span>$vars</span>);
    }<span>elseif</span>(!is_array(<span>$vars</span>)){
        <span>$vars</span> = <span>array</span>();
    }
    <span>// 合并参数</span><span>if</span>(<span>isset</span>(<span>$info</span>[<span>'query'</span>])) { <span>// 解析地址里面参数 合并到vars</span>
        parse_str(<span>$info</span>[<span>'query'</span>],<span>$params</span>);
        <span>$vars</span> = array_merge(<span>$params</span>,<span>$vars</span>);
    }

    <span>// 这里总结一下,其实就量大步骤,第一步 拆分</span><span>// 第二步:组装</span><span>// URL组装</span><span>$depr</span>       =   C(<span>'URL_PATHINFO_DEPR'</span>); <span>//'/', // PATHINFO模式下,各参数之间的分割符号</span><span>$urlCase</span>    =   C(<span>'URL_CASE_INSENSITIVE'</span>); <span>//// 默认false 表示URL区分大小写 true则表示不区分大小写</span><span>// 如果有 url 地址</span><span>if</span>(<span>$url</span>) {
        <span>if</span>(<span>0</span>=== strpos(<span>$url</span>,<span>'/'</span>)) {<span>// 定义路由  如果是跟目录</span><span>$route</span>      =   <span>true</span>;
            <span>$url</span>        =   substr(<span>$url</span>,<span>1</span>); <span>// 去掉第一个 斜杠</span><span>if</span>(<span>'/'</span> != <span>$depr</span>) { <span>// 换成系统的 指定的间隔符号</span><span>$url</span>    =   str_replace(<span>'/'</span>,<span>$depr</span>,<span>$url</span>);
            }
        }<span>else</span>{ <span>// 也就是, 不是根目录的情况下</span><span>if</span>(<span>'/'</span> != <span>$depr</span>) { <span>// 安全替换</span><span>$url</span>    =   str_replace(<span>'/'</span>,<span>$depr</span>,<span>$url</span>);
            }
            <span>// 解析模块、控制器和操作</span><span>$url</span>        =   trim(<span>$url</span>,<span>$depr</span>); <span>// 删除两端的 间隔符号</span><span>$path</span>       =   explode(<span>$depr</span>,<span>$url</span>); <span>// 解析路径</span><span>$var</span>        =   <span>array</span>();
            <span>$varModule</span>      =   C(<span>'VAR_MODULE'</span>); <span>// 'VAR_MODULE'            =>  'm',     // 默认模块获取变量</span><span>$varController</span>  =   C(<span>'VAR_CONTROLLER'</span>); <span>//'VAR_CONTROLLER'        =>  'c',    // 默认控制器获取变量</span><span>$varAction</span>      =   C(<span>'VAR_ACTION'</span>); <span>// 'VAR_ACTION'            =>  'a',    // 默认操作获取变量</span><span>$var</span>[<span>$varAction</span>]       =   !<span>empty</span>(<span>$path</span>)?array_pop(<span>$path</span>):ACTION_NAME; <span>// 通过这种方式 解析出 action</span><span>$var</span>[<span>$varController</span>]   =   !<span>empty</span>(<span>$path</span>)?array_pop(<span>$path</span>):CONTROLLER_NAME;<span>// 同上 解析出</span><span>if</span>(<span>$maps</span> = C(<span>'URL_ACTION_MAP'</span>)) { <span>// 定义路由规则 默认是没有的, 所以说,这里是不执行的</span><span>if</span>(<span>isset</span>(<span>$maps</span>[strtolower(<span>$var</span>[<span>$varController</span>])])) {
                    <span>$maps</span>    =   <span>$maps</span>[strtolower(<span>$var</span>[<span>$varController</span>])];
                    <span>if</span>(<span>$action</span> = array_search(strtolower(<span>$var</span>[<span>$varAction</span>]),<span>$maps</span>)){
                        <span>$var</span>[<span>$varAction</span>] = <span>$action</span>;
                    }
                }
            }
            <span>if</span>(<span>$maps</span> = C(<span>'URL_CONTROLLER_MAP'</span>)) { <span>// 同上</span><span>//                $a=array("a"=>"red","b"=>"green","c"=>"blue");</span><span>//                echo array_search("red",$a);</span><span>if</span>(<span>$controller</span> = array_search(strtolower(<span>$var</span>[<span>$varController</span>]),<span>$maps</span>)){
                    <span>$var</span>[<span>$varController</span>] = <span>$controller</span>;
                }
            }
            <span>if</span>(<span>$urlCase</span>) { <span>// 是否区分大小写 默认是true 代表不区分</span><span>$var</span>[<span>$varController</span>]   =   parse_name(<span>$var</span>[<span>$varController</span>]); <span>// 都转换成统一的格式</span>
            }
            <span>$module</span> =   <span>''</span>; <span>// 初始化 为空</span><span>if</span>(!<span>empty</span>(<span>$path</span>)) { <span>// 如果路径不为空</span><span>$var</span>[<span>$varModule</span>]    =   implode(<span>$depr</span>,<span>$path</span>);
            }<span>else</span>{
                <span>if</span>(C(<span>'MULTI_MODULE'</span>)) { <span>// 如果开启多模块 // 是否允许多模块 如果为false 则必须设置 DEFAULT_MODULE</span><span>if</span>(MODULE_NAME != C(<span>'DEFAULT_MODULE'</span>) || !C(<span>'MODULE_ALLOW_LIST'</span>)){
                        <span>$var</span>[<span>$varModule</span>]=   MODULE_NAME;
                    }
                }
            }
            <span>if</span>(<span>$maps</span> = C(<span>'URL_MODULE_MAP'</span>)) { <span>// 如果这里也设置路由 同上</span><span>if</span>(<span>$_module</span> = array_search(strtolower(<span>$var</span>[<span>$varModule</span>]),<span>$maps</span>)){
                    <span>$var</span>[<span>$varModule</span>] = <span>$_module</span>;
                }
            }
            <span>if</span>(<span>isset</span>(<span>$var</span>[<span>$varModule</span>])){ <span>// 同上</span><span>$module</span> =   <span>$var</span>[<span>$varModule</span>];
                <span>unset</span>(<span>$var</span>[<span>$varModule</span>]);
            }

        }
    }
    <span>// 其实这里才开始 真正的组合 分两种方式</span><span>// 域名</span><span>//</span><span>if</span>(C(<span>'URL_MODEL'</span>) == <span>0</span>) { <span>// 普通模式URL转换</span><span>$url</span>        =   __APP__.<span>'?'</span>.C(<span>'VAR_MODULE'</span>).<span>"={$module}&"</span>.http_build_query(array_reverse(<span>$var</span>));
        <span>if</span>(<span>$urlCase</span>){ <span>// 全部转化小写</span><span>$url</span>    =   strtolower(<span>$url</span>);
        }
        <span>if</span>(!<span>empty</span>(<span>$vars</span>)) { <span>// 如果参数不为空 加入参数</span><span>$vars</span>   =   http_build_query(<span>$vars</span>);
            <span>$url</span>   .=   <span>'&'</span>.<span>$vars</span>;
        }
    }<span>else</span>{ <span>// PATHINFO模式或者兼容URL模式</span><span>if</span>(<span>isset</span>(<span>$route</span>)) {<span>// 如果开启了 路由</span><span>$url</span>    =   __APP__.<span>'/'</span>.rtrim(<span>$url</span>,<span>$depr</span>);
        }<span>else</span>{
            <span>$module</span> =   (defined(<span>'BIND_MODULE'</span>) && BIND_MODULE==<span>$module</span> )? <span>''</span> : <span>$module</span>;
            <span>$url</span>    =   __APP__.<span>'/'</span>.(<span>$module</span>?<span>$module</span>.MODULE_PATHINFO_DEPR:<span>''</span>).implode(<span>$depr</span>,array_reverse(<span>$var</span>));
        }
        <span>if</span>(<span>$urlCase</span>){ <span>// 转换</span><span>$url</span>    =   strtolower(<span>$url</span>);
        }
        <span>if</span>(!<span>empty</span>(<span>$vars</span>)) { <span>// 添加参数 另外的一种解析方式而已</span><span>foreach</span> (<span>$vars</span><span>as</span><span>$var</span> => <span>$val</span>){
                <span>if</span>(<span>''</span> !== trim(<span>$val</span>))   <span>$url</span> .= <span>$depr</span> . <span>$var</span> . <span>$depr</span> . urlencode(<span>$val</span>);
            }
        }
        <span>if</span>(<span>$suffix</span>) {<span>// 如果定义了 文件后缀</span><span>$suffix</span>   =  <span>$suffix</span>===<span>true</span>?C(<span>'URL_HTML_SUFFIX'</span>):<span>$suffix</span>;
            <span>if</span>(<span>$pos</span> = strpos(<span>$suffix</span>, <span>'|'</span>)){
                <span>$suffix</span> = substr(<span>$suffix</span>, <span>0</span>, <span>$pos</span>);
            }
            <span>if</span>(<span>$suffix</span> && <span>'/'</span> != substr(<span>$url</span>,-<span>1</span>)){
                <span>$url</span>  .=  <span>'.'</span>.ltrim(<span>$suffix</span>,<span>'.'</span>);
            }
        }
    }
    <span>if</span>(<span>isset</span>(<span>$anchor</span>)){ <span>// 如果有锚点 组合上</span><span>$url</span>  .= <span>'#'</span>.<span>$anchor</span>;
    }
    <span>if</span>(<span>$domain</span>) { <span>// 组合上域名</span><span>$url</span>   =  (is_ssl()?<span>'https://'</span>:<span>'http://'</span>).<span>$domain</span>.<span>$url</span>;
    }
    <span>return</span><span>$url</span>;
}
<span>// 无 V函数</span><span>// 总结:</span><span>// 指导 parse_url 是对 url 地址进行解析的函数</span><span>// 其实我觉得这个函数他复杂了,就是对不同输入的 url 方式解析成为自己的方式</span><span>// 常用的是 U('Home/Index/index',array('name'=>'lijingshan','age'=>'12'));</span><span>// 默认的情况下 不会用域名 跟 锚点的,不过这两个还是不错的,哈哈,就是解析起来,不复杂,但是,组合的时候,那个路由规则有点费劲。</span><span>// 好的,今天我们继续</span><span>// 这个函数,其实就是个封装</span><span>/**
 * 渲染输出Widget
 *<span> @param</span> string $name Widget名称
 *<span> @param</span> array $data 传入的参数
 *<span> @return</span> void
 */</span><span><span>function</span><span>W</span><span>(<span>$name</span>, <span>$data</span>=array<span>()</span>)</span> {</span><span>return</span> R(<span>$name</span>,<span>$data</span>,<span>'Widget'</span>);
}
<span>// 无 X函数</span><span>// 无 Y函数</span><span>// 无 Z函数</span><span>// 26 字母 函数写完了,</span><span>// A 函数中调用的 函数</span><span>/**
 * 解析资源地址并导入类库文件
 * 例如 module/controller addon://module/behavior
 *<span> </span></span></code>
Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn