tp中有三种常量:
预定义常量, 这个设置后不会随环境的改变而改变的,比如 'URL_MODEL' => 1 注意是 model, 不是 url_mode
路径常量, 也不会随环境的改变而改变的, 比如 define('THINK_PATH', './ThinkPHP/'), define('LIB_PATH', THINK_PHP.'Library/');
系统常量, 这个会随着环境/文件的不同而不同的, 比如: 在模板中常用到的各种地址和名字等 : __ROOT__, __CONTROLLER__, __CONTROLLER_NAME__
等等
命名空间和根命名空间?
根命名空间, 有两个, 一个是 LIB_PATH下的各个子目录,和 APP_PATH下的各个模块目录; 是不是总共有三个根命名空间? ? 还包括: 网站的根目录??
相应的, 核心类的起始命名空间是LIB_PATH, 应用的模块的 "起始命名空间" 是 APP_PATH, 即应用所在目录.
- 定义类的时候, 指定namespace从 模块名写起, 不用反斜杠:
namespace HomeController;
- 要引用基类的时候, 从Think写起, 不用反斜杠:
use ThinkController;
如果不用use, 可以直接写继承基类:
class FooController extends ThinkController { ...}
- 凡是要在函数中, new/初始化一个对象, 要用反斜杠 开头, 比如:
new ThinkFoo();
要使用 php这种语言本身内置的类, 或 第三方没有使用命名空间的类/类库, 要从 根命名空间, 网站的根路径 (这时候的 起始命名空间就是网站的根路径
) 开始写起?? 比如: $class= new stdClass(); $xml= new SimpleXmlElement($xmlStr);
tp的配置文件
- 全局函数 C 支持类似三元运算符的形式, 如果没有设置该配置名称, 则取默认值:
$name = C('user_name', null, 'anonymous_user');
- C 函数支持二维配置, 比如:
C('USER_CONFIG.USER_TYPE');
配置文件加载的顺序?
惯例-> 应用公共配置 -> 模式(这个一般不用)->模块配置->调试-> 模块的扩展配置 -> 动态配置.
动态配置支持 批量配置. 即 C($multi_config) 多个配置项组成的数组
默认情况下, 应用下面的子目录模块 , 都可以访问(当然除了 Common, Runtime模块外), 你可以通过设置:
MODULE_ALLOW_LIST, 或 MODULE_DENY_LIST, 或 MULTI_MODULE =>false, DEFAULT_MODULE => 'Home' 等来设置
公共模块 Common 可以通过设置 ' define('COMMON_PATH', ....)` 来设置, 以增加安全,实际上, 一般都没有必要.
因为, 你要注意, 如果公共模块没有设置在Application下, 那么就不会创建父目录Common, 即 公共函数目录和公共配置目录将会散放在某个目录中,
即Common和Conf将没有父目录Common.
你可以同时绑定模块和控制器, 这时访问时就可以省略(而且必须省略, 不省略会报错"非法的操作! "!! )模块和控制器名称, 直接写操作名称.
因为一个入口文件, 同时只能创建一个模块, 因此, 要创建多个模块, 要么你使用多个入口(每个入口对应一个模块), 要么你要对一个入口文件进行修改...
### 一直搞不懂tp的url_case_insensitive是怎样的, 好像只是支持 "首字母不区分大小写", 好像并不支持模块控制器的完全的大小写混合: 只是支持: 模块和控制器首字母可以是大写或小写, 但是中间字母必须是小写, 操作的名称可以是任意的大小写混合. 而实际上, 用户在访问网站的时候, 也是通过页面内的导航链
接, 而不是通过地址栏输入的, 所以, 只要在代码内严格区分大小写就是了, 事实上, 在linux中, 严格区分大小写也是一种基本常识.
对于复杂的应用, 也只要三个模块: Home, Admin(用于后台文章/数据管理) , User(用户信息/数据管理) 就可以了.一般的应用, 比如企业宣传网站, 只要一个单模
块 Home 就足够了.
### 多个模块之间的链接/跳转 U方法???? 1. 使用 跨控制器/跨模块/跨应用的调用函数是A或R函数 1. 链接方法是:.... 调用 U方法! - U方法 只能支持在 同一个应用/同一个项目内的 地址链接跳转( 可以支持 跨模块/ 跨控制器/跨操作的 地址链接跳转), 不能跨域支持. 所谓地址表达式 后面的 `@ 域名` 也只是域名的别名, 就是要求这两个域名必须指向同一个应用. - U方法 共有四个参数, ``第一个是地址表达式, 第二个是通过url地址所传参数, 第三个是 '是否获取为静态后缀名', 第四个是 '是否显示域名', 就是 url地址前面的 `http://domain/` - U方法等全局函数, 可以在任何地方都可以使用, 可以在 控制器/操作方法中使用, 也可以在 模板.html文件中使用.. - 模板中使用的变量? 要注意 , 模板文件是html文件, 不是php文件! 所以 你不能使用 `$变量`, 也不能使用 `类似define这样的常量`, 所以 你要使用的 _ _ TempName_ _ 这种形式的东西, 叫做 "模板常量"
if(isset($anchor)){
$url .= '#'.$anchor;
}
if($domain) {
$url = (is_ssl()?'https://':'http://').$domain.$url;
}
return $url;
### 关于模板常量?? 在tp 3.2.3中的 TMPL_PARSE_STRING?
----------------------
tp 自动创建多个控制器和模型?
模块, 控制器, 模型等 可以自己手动创建, 也可以用代码自动创建, 在事先规划好了之后, 用这种自动生成的方式还是很方便的
define('BIND_MODULE', 'User');
define('BUILD_CONTROLLER_LIST', 'UserLogReg,UserManage'); // 这个逗号后, 不能有空格, 否则, 空格会作为控制器名称的一部分
define('BUILD_MODEL_LIST', 'UserLogModel,UserManageModel');
或者, 直接调用 Think下的Build类方法: 注意buildController 和 BUILD_CONTROLLER_LIST的区别: 后者是一个整体的字符串, (因为默认
隐含就知道了是哪个模块), 而前者 必须指明 模块名和控制器名称$module, $controller
, 所以 一次调用只能生成一个控制器.
require THINK_PATH.'ThinkPHP.php';
/* 下面的内容要放在 框架入口文件 ThinkPHP.php 的最后! */
ThinkBuild::buildController('User', 'UserLogReg'); // 默认的Index控制器不需要创建
ThinkBuild::buildController('User', 'UserManage');
ThinkBuild::buildModel( 'User', 'UserLogModel');
### 注意, thinkphp下面的类的 函数名称, 第一个单词的首字母 是小写的, 然后如果有后面单词的, 首字母才大写, 以 IndexController类的 index方法为记住
.
控制器和模型的理解?
控制器, 是对 相同或相关 对象/事物 的 一些/一系列的 相关操作的集合. 因此, 操作相当于函数, 操作用函数来实现, 那么将一系列相关函数 进行封装的,
就是类.
所以控制器是 类. (一大类 相关操作 的集合)
模型, 是表, 因为在tp开发中, 只有一个数据库, 数据库下面是表, 要对表进行相关操作, 操作是函数, 所以 表就是 Model模型类, Model模型类封装的函数, 就是
对表进行 操作的 一系列相关函数.
is_file和 is_dir等文件操作函数?
// 创建控制器类
static public function buildController($module,$controller='Index') {
$file = APP_PATH.$module.'/Controller/'.$controller.'Controller'.EXT;
if(!is_file($file)){
$content = str_replace(array('[MODULE]','[CONTROLLER]'),array($module,$controller),self::$controller);
if(!C('APP_USE_NAMESPACE')){
$content = preg_replace('/namespaces(.*?);/','',$content,1);
}
$dir = dirname($file);
// is_file()和is_dir()需要参数表示的文件/目录要存在而且有效,才为真,所以大多数的时候,是用来判断文件或目录是否存在的!
// 相当于使用 file_exists/dir_exists只是没有这样的函数
// 创建目录的函数 是:mkdir, 不是makedir...
if(!is_dir($dir)){
mkdir($dir, 0755, true);
}
// file_put_contents()函数,相当于fopen + fwrite +fclose, 所以肯定愿意使用这个!
file_put_contents($file,$content);
}
}
clearstatcache()函数的目的是?
- 这个主要是用在对文件的操作上, 因为对文件的操作函数,很多函数都对结果进行了缓存,而当对文件进行了**修改/写入/删除等操作后,函数的操作结果就要改变
了,但是下一次执行同样的操作时取出的是之前缓存的结果,这个就不对了,所以需要在 编辑/修改/删除文件等操作后, 要对之前的 缓存结果进行 清除,这样才能得
到真实的结果.
clearstatcache(): 删除文件缓存信息 , 在很多文件操作函数之后,要进行这个操作, 否则再次得到的结果可能会出错.
static和访问符public/private/protected的先后位置可以是 任意的,这个在很多地方都看到的。
除了case语句外, 通常在编程的结构化语句中, 都不推荐直接使用"常量,数值型的常量",而是将常量/常数值等赋值给变量,要充分使用变量, 要深刻理解变量
的作用,变量的作用主要就是用来接收常量常数的赋值的, 在结构化语句中尽量使用变量,这样以后修改起来,只需要给变量赋予不同的值就好了, 也可以在函数中传
入不同的数值给参数变量, 这样就不必修改后面的程序代码了.
要注意,dirname($file),获取的目录字符串, 最后面是没有斜杠的,所以如果后面要连接子目录的话, 要在子路经的前面加上 斜杠/,否则前面的字符串
就会和后面的子目录字符串连接在一起。 比如:$dir = dirname($file) . '/test/'
如果test前面没有斜杠的话,就成了wwwtest/目录,而不是 www/test/
URL_MODEL的问题 如果你的应用下面的模块都采用统一的url模式(模型,是URL_MODEL),就可以在应用项目的公共配置文件中设置url模式,如果不同的模块需
要设置不同的url模式,就应该在模块配置中设置url模式。
- 即使是 pathinfo的url模式, 也支持问号 get传参的格式
- pathinfo模式中, 分隔符可以定制:
'URL_PATHINFO_DEPR' => '-'
要搞清楚 convention.php配置 文件中一些配置项的作用和含义是什么?
- 比如: VAR_MODULE, VAR_CONTROLLER, ... 是指在pathinfo的 url_model中, 为了获取url地址中的 模块值, 控制器和操作的值, 需要用什么变量名 来获取
, 即在 程序中通过超全局变量 $module = $_GET['VAR_MODULE => 所对应的配置值, 默认的是m']
来取得模块名...
- 又比如: 'DEFAULT_C_LAYER' => 'Controller', 'DEFAULT_M_LAYER' => 'Model' 是为了解决 复杂应用中, 使用多层设计时, 比如数据层 都是从 Model继承,
但是分成 UserModel, UserLogic, UserService三层. 这三层的操作都是类似的, 都是 用 D(...)函数来初始化的. 那么 这三层究竟哪一层是默认的Model层呢? 因
为默认的模型层, 用D('User') 来初始化, 其他层就要加上 层的名字, 比如: D('User', 'Logic'), 或 D('User', 'Service');
- 说到tp的多层设计, 视图层View的多层设计是通过 目录来实现的, 比如 根据主题Theme/Default+Blue等来实现分层; 而控制器层, 是通过 业务控制器和
事件控制器等来实现分层的, 而模型类的分层也是类似的....
- **但是 , 要注意 ,在 VAR_MODULE, VAR_CONTROLLER, VAR_ACTION, 三个变量中, VAR_MODULE 变量 必须在 应用配置文件, 即
Application/Common/Conf/config.php 中配置, 其他两个变量 可以 在 模块配置文件中配置.**
在多个控制器, 模块, 项目/应用 之间的协同操作: 当然在同一个控制器内部的函数, 是可以随意的互相调用的, 因为一个控制器(就是类) 内部的任何函数(
即使是private) 都是相互可见的, 但是要在一个控制器内的某个操作函数中, 调用另一个控制器的方法, 或者 调用 另一个模块中(比如前台或后台模块之间的) 的
控制器方法, 甚至调用 另一个/其他 应用的方法. tp提供了A方法和 R方法, 就是用来实现这个母的的.
- A方法和R 方法是实现 跨 控制器/跨模块/跨应用之间的 方法调用
- A方法仅仅是 实例化 控制器类对象, 而R方法是在 A对象基础上, 更进一步, 直接调用控制器的方法
- A或者R调用的格式是: 如果是同一模块内跨控制器, 用
A('User') ; R('User/fooMethod');
, 跨模块的话, 用 : `A('Admin/User'); R
('Admin/User/fooMethod'); , 如果是跨应用的话,
A('AnotherApp://User/fooMethod'); `, 所以, 如果是跨应用的话, 格式类似于 网站的格式:
http://User/fooMethod
关于二进制文件和文本文件的区别?
- php中对文件的操作函数, 很多都要进行 判断, 用if(...)判断每一步的操作是否成功, 比如 首先要判断文件打开是否成功, 成功后才能继续操作, 要判断文
件写入是否成功,, 成功后才能继续后面的操作...?
- 如果对文件的操作比较信任, 相信不会出错, 那么你可以省略fopen, fread, fwrite, fclose这一系列的操作, 直接使用`file_put_contents(..), 或
file_get_contents(..)` 更高效.
-
文件文件和二进制文件并没有本质上的差别, 在物理存储上, 都是存储的比特流. 读取的时候, 都是读取的比特流。
-
任何一个文件, 如果操作系统允许, 你可以用二进制打开,也可以用文本编辑器打开, 只不过读取的是乱码而已.
- 只有在windos上才区分文本文件和二进制文件,在类linux系统上都不区分它们的
- 区别是它们的编码、解码/译码的方式不一样
- 文本文件的编码和译码是以 字符编码/定长(gbk2个字节/ascii1个字节/utf3个字节)来进行的, 而二进制文件是以值编码的, 是变长/不定长比特流/字节流编码
的, 可能是一个字节表示一个意思, 可能是多个字节合起来表示某个功能或作用, 甚至是某一个比特位的不同取值表示某个含义...因此, 二进制文件的编码规则是
非常灵活/多变/自由/复杂的. 所以,你解码/译码的时候, 也就要求必须知道文件原来的编码方式或编码规则/编码器. 用对应的编码器或解码器才能. 否则就不能
打开...
- 在可读性上, 由于文本文件会按 定长字节依次读取, 并按定长字节的规则进行解码/译码, 所以读出的都是"可读human-readable"字符. 可读性好. 而二进制文
件, 每个字节单独来看, 并没有确切的/有意义的意思, 所以, 你一个字节一个字节的 用记事本程序读出来时, 必然是乱码.
-
在存储效率上, 二进制文件的效率更高, 因为你甚至可以 用一个比特位来存储/表示 信息...
-
在windows中, 除了文本文件.txt外,其他文件基本上都是二进制文件,比如: 图片文件, 音频/视频文件/ word文件等等.
-
二进制文件 是变长值 编码, 可能 "00000000 00000000 00000000 00000001" 表示一个四字节的整数 int 1 , 但是如果用文本文件来解析的话, 就变成 四个
特殊的控制字符了. 很明显跟 实际的含义就差得太远了. 用hex查看文件 那些显示的 空白或点点 就表示的是 "不可见, 不可读"的 控制字符/ 特殊字符.
- 所谓二进制安全函数, 是指 这些函数在操作 二进制文件的时候, 不会损坏 源文件的内容...
在php中所说的二进制安全?
主要是针对 字符串操作函数 来说的. 针对于比特率中的 等特殊字符字节而言的. 因为php来源于c语言. 在C语言中, 针对字符串操作的函数, 在遇到 ' '
''...等 字符时, 会作为特殊字符来处理, 将会结束函数操作.
php函数二进制安全,是说, 在处理从文件中读取到的 比特流, 会将所有的字符 都一视同仁, 不会担心有特殊字符影响处理, 不用担心特殊编码字节字符 的影响,
php "二进制安全" 函数, 会将 字符当成普通字符处理, 不会当做字符串结束符. 后面的字符继续接受处理.
### 一个基本常识, 在函数中, 最好不要直接 用 echo /print 等输出语句来 输出字符串等内容, ,最好是 返回 某个数值 , 或返回 某个 字符串. 这样, 一个是便于调用函数的时候, 统一的知道 用 echo , print等来输出, 更重要的是, 可以让 函数 的调用, 返回值 可以和 字符串或 数字等 进行 相连 或 相加等操
作 ....
标签和行为?
- 行为发生作用的位置 就是 标签(位). 也成为 "钩子"
- 当程序执行到某个标签位置的时候, 就会被拦截下来, 统一执行相关的行为. 类似AOP编程中的 "切面 " 概念
- 给标签绑定行为的方式 就类似于 aop编程的思想.
- ??? 标签位置的定义是放在 控制器类的操作/方法中 , 用
ThinkHook::listen('tag_name', $params);
绑定标签 和行为是在 tag.php文件中进行定义
: return array( 'tag_name1' => '/path/to/behavior1', ....);
标签 默认的 会首先 绑定 系统行为, 如果要 取消系统行为/ 覆盖系统行为, 需要使
用 在 标签文件中 使用 '_overlay' => true ????
-
可以单独的, 直接调用行为
echo B('CheckFooBehavior');
-
**行为扩展和函数的区别? ** 行为扩展是tp系统底层的一种 架构扩展, 是标签位和行为的绑定, 类似于 aop编程思想, 不管什么时候, 只要执行到标签位, 程
序就被拦截下来. 自动执行规定的行为. 而函数,是要 显式地调用的 .
- CBD模式: 是指 CORE, BEHAVIOR DRIVER. 在Think下, 除了核心类 之外, 基本上就是 对应的 驱动文件所在的目录 Driver.
类库和类库文件?
通常来说, 类库 library, 是表示的 目录 , 是 文件夹,
类 / 类文件, 类库文件 应该目录下的 文件. file.
类库映射?
-
目的: 是指, 在命名空间很多的时候, 为了提高加载效率而建立的类库文件 的 映射 /别名. 这样在初始化类对象的时候, 就不用管命名空间, 直接加载了.
-
添加类库映射的方法是:
-
??? 在操作方法中, 在要初始化对象实例之前, 用Think类的静态方法
ThinkThink::addMap('ThinkLog', THINK_PATH.'ThinkLog.php') ....
addMap静态方法, 也支持 批量导入 类库映射, 使用 数组做为addMap的参数.. -
在 模块配置目录Conf下, 建立 alias.php 文件 , 在别名文件中创建映射:
return array(
'ThinkLog' => THINK_PATH.'ThinkLog.php',
...
//
);
- 类库文件自动加载的优先顺序? 比如 :
TestMy.class.php
注意Test前面加上反斜杠和不加的区别!
首先是 你定义的类库映射;
然后是 系统的类库目录下面的命名空间, 如: LIB_PATH . '/ Foo/Bar.class.php'
然后是 你定义的 注册命名空间, 用AUTOLOAD_NAMESPACE' => ...
最后是 应用项目的 模块 下的子目录...
最后, 不管是哪里的类文件, 都可以用 import 手动加载: import('Class_Name', '加载的相对目录', '非默认的文件后缀')
正有点混乱!
### 总之, 关于tp中的类库加载问题就清楚了: 首先, 类库(文件) 的加载问题, 是针对 类对象初始化 实例化 这个问题而言的. 因为你要初始化类对象, 你首
先得要 加载这个类对象的类; 也就是是, 要让tp系统 能够找得到这个类, 知道在哪里去加载这个类(是通过 命名空间 来 告诉tp 加载类所在的位置, 因为
namespace所在的目录位置, 跟 类名 是一致的...) 第二, tp加载类, 可以有两种方式, 一种是通过自动加载的方式, 优先级顺序是: 类库映射(别名) ->
LIB_PATH下的子目录(根命名空间) -> 自定义注册的namespace -> 应用项目下的模块 中的类. 另一种方式是, 通过手动加载的方式, 即不管什么 namespace, 我
在要实例化一个;类对象的时候, 就用import 函数去手动 加载这个类...
关于 编译缓存?
- 编译缓存的原理是: 第一次运行的时候, 将tp核心需要加载的文件 去掉空白和注释合并到一个文件中。 以后运行时, 直接加载编译过的缓存文件, 省去很
多io开销, 加快执行速度。
缓存文件的命名是: 应用模式~runtime.php 比如: common~runtime.php, 或者: sae~runtime.php 这里的common是应用模式.
.
- 另一种使用缓存文件的方式是 使用lite文件。
- lite : adj.
清淡的; 低糖的, 低盐的, 低脂的, 低热量的... - 在什么时机? 生成lite文件, 是在 生产环境下, 关闭调试模式后, 就可以生成lite文件
- 在入口文件中 , 定义
define(' BUILD_LITE_FILE', true) ;
这样执行入口文件后, 就会生成 lite.php 文件, 这个是默认的lite文件名 - 可以自己制定lite文件的名称和路径: 在 应用配置文件App/Common/Conf/config.php中, 定义
'RUNTIME_LITE_FILE' => APP_PATH . 'lite.php'
- 具体规定lite.php中要编译缓存的内容是: 在 应用配置目录下 App/Common/Conf下 或你前面制定的路径下, 新建lite.php文件 并输入:
return array(
THINK_PATH.'Common/functions.php',
COMMON_PATH.'Common/function.php', // 公共模块中的函数 , 文件名称 一定要用 function.php , 不能用 复数的functions!
CORE_PATH.'Think'.EXT,
CORE_PATH.'Hook'.EXT,
CORE_PATH.'App'.EXT,
....
BEHAVIOR_PATH.'ParseTemplateBehavior'.EXT,
BEHAVIOR_PATH.'ContentReplaceBehavior'.EXT,
等等...
);
所有在lite.php中定义的文件都会 纳入lite文件的编译缓存中 , 当然 还可以对已经生成的lite.php文件进行修改
关于Behavior的设置?
- 定义自己的行为, 在模块目录下创建一个Behavior目录, 然后将自己的行为类文件 放在HomeBehaviorMyBehavior.class.php中。
- 行为标签绑定文件, 可以放在项目 或 模块的 Behavior目录中, 因为绑定行为时使用的是完整路径。
很重要的一个概念: 编译缓存文件或 lite.php文件, 应该放在 应用/项目的 配置目录中, 这样多个模块 前台/后台都可以 使用这个缓存文件; 当我们修
改了 应用或模块的配置文件, 修改了载入到缓存文件中的类文件之后, 就应该重新 去生成 缓存编译文件, 否则, 继续使用原来的缓存文件就会出错!
lite文件生成后, 就可以将原来的 "框架入口文件" (注意不是index.php文件), 替换为 lite.php: 即 : `将 require THINK_PATH. 'ThinkPHP.php' ;
语句该成: require './Runtime/lite.php' ; `
当生成和替换 lite文件后, 应用的编译缓存 就不再需要了...
控制器 到模板 的变量输出?
-
在模板中, 输出变量使用
{$**}
的方式, 输出函数 使用{: **}
的方式 -
使用 assign方法, assign方法 的 参数是两个, 一个必须 有 变量名, 一个是变量值. 相当于 等号赋值的 变化方式. 比如:
$this -> assign( 'cart', $cart);
就表示给cart这个要传递到模板的变量 赋值为$cart
. 否则, 如果直接写$this -> assgin($cart)
那么 这个cart值 其实是没有 付给 任何变量的, 所以, 你在 模板文件中, 输出{$cart}
得到的结果只能是空, 因为根本就没有 cart变量. -
如果模板变量是 数组, 可以用 点语法 和 中括号输出 都可以 , 如果是 对象, 支持 冒号和 箭头语法输出 都可以 , 比如:
{$arr.name} {$arr['name']}, {$person::name}, {$person->name}
但是 建议 还是 用比较传统的方式输出, 即 数组 使用 中括号语法, 对象使用 箭头语法:{$arr['name']}, {$person->name}
-
整个模板变量, 只有 两种, 一种是 普通的 通过 assign 赋值的模板变量; 另一种就是 所谓的系统变量, 所有的系统 变量, 统一的用 同一种 方式输出, 就是:
$Think.**
支持: 超全局变量, 如$_SERVER; 常量; 配置变量, 语言变量等等. -
有时候, 我们可能不只是 要 原样输出模板变量, 还可能需要输出 经过函数处理/ 四则运算符处理后的 模板变量 , 这时 , 可以借鉴 linux 中 "管道" 的 思想, 把前面的模板变量作为 后面的函数处理的 管道 输入: 即
{$name|md5|strtoupper|substr=###, 1, 3}
也支持默认值:{$name|default='默认名称'|substr=###, 1,3 }