当前位置: 首页 > news >正文

做网站需要具备的基础条件wordpress改为直接填写密码

做网站需要具备的基础条件,wordpress改为直接填写密码,点卡网站怎么做,跨境电商热销产品排行基础#xff1a; 1. 基础概念 LAMP LAMP是基于Linux#xff0c;Apache#xff0c;MySQL和PHP的开放资源网络开发平台。这个术语来自欧洲#xff0c;在那里这些程序常用来作为一种标准开发环境。名字来源于每个程序的第一个字母。每个程序在所有权里都符合开放源代码标准 1. 基础概念 LAMP LAMP是基于LinuxApacheMySQL和PHP的开放资源网络开发平台。这个术语来自欧洲在那里这些程序常用来作为一种标准开发环境。名字来源于每个程序的第一个字母。每个程序在所有权里都符合开放源代码标准Linux是开放系统Apache是最通用的网络服务器MySQL是带有基于网络管理附加工具的关系数据库PHP是流行的对象脚本语言它包含了多数其它语言的优秀特征来使得它的网络开发更加有效。开发者在Windows操作系统下使用这些Linux环境里的工具称为使用WAMP。虽然这些开放源代码程序本身并不是专门设计成同另外几个程序一起工作的但由于它们都是影响较大的开源软件拥有很多共同特点这就导致了这些组件经常在一起使用。在过去的几年里这些组件的兼容性不断完善在一起的应用情形变得更加普遍。并且它们为了改善不同组件之间的协作已经创建了某些扩展功能。目前几乎在所有的Linux发布版中都默认包含了这些产品。Linux操作系统、Apache服务器、MySQL数据库和Perl、PHP或者 Python语言这些产品共同组成了一个强大的Web应用程序平台。随着开源潮流的蓬勃发展开放源代码的LAMP已经与J2EE和.Net商业软件形成三足鼎立之势并且该软件开发的项目在软件方面的投资成本较低因此受到整个IT界的关注。从网站的流量上来说70%以上的访问流量是LAMP来提供的LAMP是最强大的网站解决方案 OOP 面向对象编程Object Oriented ProgrammingOOP面向对象程序设计是一种计算机编程架构。OOP 的一条基本原则是计算机程序是由单个能够起到子程序作用的单元或对象组合而成。OOP 达到了软件工程的三个主要目标重用性、灵活性和扩展性。为了实现整体运算每个对象都能够接收信息、处理数据和向其它对象发送信息。OOP 主要有以下的概念和组件 组件  数据和功能一起在运行着的计算机程序中形成的单元组件在 OOP 计算机程序中是模块和结构化的基础。 抽象性  程序有能力忽略正在处理中信息的某些方面即对信息主要方面关注的能力。 封装  也叫做信息封装确保组件不会以不可预期的方式改变其它组件的内部状态只有在那些提供了内部状态改变方法的组件中才可以访问其内部状态。每类组件都提供了一个与其它组件联系的接口并规定了其它组件进行调用的方法。 多态性  组件的引用和类集会涉及到其它许多不同类型的组件而且引用组件所产生的结果得依据实际调用的类型。 继承性  允许在现存的组件基础上创建子类组件这统一并增强了多态性和封装性。典型地来说就是用类来对组件进行分组而且还可以定义新类为现存的类的扩展这样就可以将类组织成树形或网状结构这体现了动作的通用性。 由于抽象性、封装性、重用性以及便于使用等方面的原因以组件为基础的编程在脚本语言中已经变得特别流行。 MVC MVC是一个设计模式它强制性的使应用程序的输入、处理和输出分开。使用MVC应用程序被分成三个核心部件模型M、视图V、控制器C它们各自处理自己的任务。 视图 视图是用户看到并与之交互的界面。对老式的Web应用程序来说视图就是由HTML元素组成的界面在新式的Web应用程序中HTML依旧在视图中扮演着重要的角色但一些新的技术已层出不穷它们包括Adobe Flash和象XHTMLXML/XSLWML等一些标识语言和Web services。如何处理应用程序的界面变得越来越有挑战性。MVC一个大的好处是它能为你的应用程序处理很多不同的视图。在视图中其实没有真正的处理发生不管这些数据是联机存储的还是一个雇员列表作为视图来讲它只是作为一种输出数据并允许用户操纵的方式。 模型 模型表示企业数据和业务规则。在MVC的三个部件中模型拥有最多的处理任务。例如它可能用象EJBs和ColdFusion Components这样的构件对象来处理数据库。被模型返回的数据是中立的就是说模型与数据格式无关这样一个模型能为多个视图提供数据。由于应用于模型的代码只需写一次就可以被多个视图重用所以减少了代码的重复性。 控制器 控制器接受用户的输入并调用模型和视图去完成用户的需求。所以当单击Web页面中的超链接和发送HTML表单时控制器本身不输出任何东西和做任何处理。它只是接收请求并决定调用哪个模型构件去处理请求然后确定用哪个视图来显示模型处理返回的数据。 现在我们总结MVC的处理过程首先控制器接收用户的请求并决定应该调用哪个模型来进行处理然后模型用业务逻辑来处理用户的请求并返回数据最后控制器用相应的视图格式化模型返回的数据并通过表示层呈现给用户。 ORM 对象-关系映射Object/Relation Mapping简称ORM是随着面向对象的软件开发方法发展而产生的。面向对象的开发方法是当今企业级应用开发环境中的主流开发方法关系数据库是企业级应用环境中永久存放数据的主流数据存储系统。对象和关系数据是业务实体的两种表现形式业务实体在内存中表现为对象在数据库中表现为关系数据。内存中的对象之间存在关联和继承关系而在数据库中关系数据无法直接表达多对多关联和继承关系。因此对象-关系映射(ORM)系统一般以中间件的形式存在主要实现程序对象到关系数据库数据的映射。面向对象是从软件工程基本原则(如耦合、聚合、封装)的基础上发展起来的而关系数据库则是从数学理论发展而来的两套理论存在显著的区别。为了解决这个不匹配的现象,对象关系映射技术应运而生。 AOP AOPAspect-Oriented Programming面向方面编程可以说是OOPObject-Oriented Programing面向对象编程的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候OOP则显得无能为力。也就是说OOP允许你定义从上到下的关系但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切cross-cutting代码在OOP设计中它导致了大量代码的重复而不利于各个模块的重用。而AOP技术则恰恰相反它利用一种称为“横切”的技术剖解开封装的对象内部并将那些影响了多个类的公共行为封装到一个可重用模块并将其名为“Aspect”即方面。所谓“方面”简单地说就是将那些与业务无关却为业务模块所共同调用的逻辑或责任封装起来便于减少系统的重复代码降低模块间的耦合度并有利于未来的可操作性和可维护性。AOP代表的是一个横向的关系如果说“对象”是一个空心的圆柱体其中封装的是对象的属性和行为那么面向方面编程的方法就仿佛一把利刃将这些空心圆柱体剖开以获得其内部的消息。而剖开的切面也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原不留痕迹。使用“横切”技术AOP把软件系统分为两个部分核心关注点和横切关注点。业务处理的主要流程是核心关注点与之关系不大的部分是横切关注点。横切关注点的一个特点是他们经常发生在核心关注点的多处而各处都基本相似。比如权限认证、日志、事务处理。Aop 的作用在于分离系统中的各种关注点将核心关注点和横切关注点分离开来。正如Avanade公司的高级方案构架师Adam Magee所说AOP的核心思想就是“将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。” CURD CURD是一个数据库技术中的缩写词一般的项目开发的各种参数的基本功能都是CURD。它代表创建Create、更新Update、读取Read和删除Delete操作。CURD 定义了用于处理数据的基本原子操作。之所以将CURD 提升到一个技术难题的高度是因为完成一个涉及在多个数据库系统中进行CURD操作的汇总相关的活动其性能可能会随数据关系的变化而有非常大的差异。CURD在具体的应用中并非一定使用create、update 、read和delete字样的方法但是他们完成的功能是一致的。例如ThinkPHP就是使用add、save、select和delete方法表示模型的CURD操作。 ActiveRecord Active Record中文名活动记录是一种领域模型模式特点是一个模型类对应关系型数据库中的一个表而模型类的一个实例对应表中的一行记录。Active Record 和 Row Gateway 行记录入口十分相似但前者是领域模型后者是一种数据源模式。关系型数据库往往通过外键来表述实体关系Active Record 在数据源层面上也将这种关系映射为对象的关联和聚集。   Active Record 适合非常简单的领域需求尤其在领域模型和数据库模型十分相似的情况下。如果遇到更加复杂的领域模型结构例如用到继承、策略的领域模型往往需要使用分离数据源的领域模型结合 Data Mapper 数据映射器使用。Active Record 驱动框架一般兼有 ORM 框架的功能但 Active Record 不是简单的 ORM正如和 Row Gateway 的区别。由Rails最早提出遵循标准的ORM模型表映射到记录记录映射到对象字段映射到对象属性。配合遵循的命名和配置惯例能够很大程度的快速实现模型的操作而且简洁易懂。 单一入口 单一入口通常是指一个项目或者应用具有一个统一但并不一定是唯一的入口文件也就是说项目的所有功能操作都是通过这个入口文件进行的并且往往入口文件是第一步被执行的。单一入口的好处是项目整体比较规范因为同一个入口往往其不同操作之间具有相同的规则。另外一个方面就是单一入口带来的好处是控制较为灵活因为拦截方便了类似如一些权限控制、用户登录方面的判断和操作可以统一处理了。或者有些人会担心所有网站都通过一个入口文件进行访问是否会造成太大的压力其实这是杞人忧天的想法。 2. 目录结构 目录/文件说明ThinkPHP.php框架入口文件Common框架公共文件目录Conf框架配置文件目录Lang框架系统语言目录Lib系统核心基类库目录Tpl系统模板目录Extend框架扩展目录关于扩展目录的详细信息请参考后面的扩展章节注意如果你下载的是核心版本有可能Extend目录是空的因为ThinkPHP本身不依赖任何扩展。 3. 命名规范 使用ThinkPHP开发的过程中应该尽量遵循下列命名规范 类文件都是以.class.php为后缀这里是指的ThinkPHP内部使用的类库文件不代表外部加载的类库文件使用驼峰法命名并且首字母大写例如DbMysql.class.php确保文件的命名和调用大小写一致是由于在类Unix系统上面对大小写是敏感的而ThinkPHP在调试模式下面即使在Windows平台也会严格检查大小写类名和文件名一致包括上面说的大小写一致例如 UserAction类的文件命名是UserAction.class.php InfoModel类的文件名是InfoModel.class.php 并且不同的类库的类命名有一定的规范函数、配置文件等其他类库文件之外的一般是以.php为后缀第三方引入的不做要求函数的命名使用小写字母和下划线的方式例如 get_client_ip方法的命名使用驼峰法并且首字母小写或者使用下划线“_”例如 getUserName_parseType通常下划线开头的方法属于私有方法属性的命名使用驼峰法并且首字母小写或者使用下划线“_”例如 tableName、_instance通常下划线开头的属性属于私有属性以双下划线“__”打头的函数或方法作为魔法方法例如 __call 和 __autoload常量以大写字母和下划线命名例如 HAS_ONE和 MANY_TO_MANY配置参数以大写字母和下划线命名例如HTML_CACHE_ON语言变量以大写字母和下划线命名例如MY_LANG以下划线打头的语言变量通常用于系统语言变量例如 _CLASS_NOT_EXIST_对变量的命名没有强制的规范可以根据团队规范来进行ThinkPHP的模板文件默认是以.html 为后缀可以通过配置修改数据表和字段采用小写加下划线方式命名并注意字段名不要以下划线开头例如 think_user 表和 user_name字段类似 _username 这样的数据表字段可能会被过滤。在ThinkPHP里面有一个函数命名的特例就是单字母大写函数这类函数通常是某些操作的快捷定义或者有特殊的作用。例如ADSL方法等等。 另外有一点非常关键ThinkPHP默认全部使用UTF-8编码所以请确保你的程序文件采用UTF-8编码格式保存并且去掉BOM信息头去掉BOM头信息有很多方式不同的编辑器都有设置方法也可以用工具进行统一检测和处理否则可能导致很多意想不到的问题。 4. CBD架构 ThinkPHP3.0版本引入了全新的CBD核心Core行为Behavior驱动Driver架构模式因为从底层开始框架就采用核心行为驱动的架构体系核心保留了最关键的部分并在重要位置设置了标签用以标记其他功能都采用行为扩展和驱动的方式组合开发人员可以根据自己的需要对某个标签位置进行行为扩展或者替换就可以方便的定制框架底层也可以在应用层添加自己的标签位置和添加应用行。而标签位置类似于AOP概念中的“切面”行为都是围绕这个“切面”来进行编程如果把系统内置的核心扩展看成是一种标准模式的话那么用户可以把这一切的行为定制打包成一个新的模式所以在ThinkPHP里面称之为模式扩展事实上模式扩展不仅仅可以替换和增加行为还可以对底层的MVC进行替换和修改以达到量身定制的目的。利用这一新的特性开发人员可以方便地通过模式扩展为自己量身定制一套属于自己或者企业的开发框架新版的模式扩展是框架扩展的集大成者开创了新的里程碑这正是新版的真正魅力所在。 5. 开发流程 使用ThinkPHP创建应用的一般开发流程是 系统设计、创建数据库和数据表可选项目命名并创建项目入口文件开启调试模式完成项目配置创建项目函数库可选开发项目需要的扩展模式、驱动、标签库等可选创建控制器类创建模型类可选创建模板文件运行和调试、分析日志开发和设置缓存功能可选添加路由支持可选安全检查可选 部署到生产环境。 6. 入口文件 ThinkPHP采用单一入口模式进行项目部署和访问无论完成什么功能一个项目都有一个统一但不一定是唯一的入口。应该说所有项目都是从入口文件开始的并且所有的项目的入口文件是类似的入口文件中主要包括 定义框架路径、项目路径和项目名称可选定义调试模式和运行模式的相关常量可选载入框架入口文件必须 7. 项目目录 生成的项目目录结构和系统目录类似包括 目录说明Common项目公共文件目录一般放置项目的公共函数Conf项目配置目录项目所有的配置文件都放在这里Lang项目语言包目录可选 如果不需要多语言支持 可删除Lib项目类库目录通常包括Action和Model子目录Tpl项目模板目录支持模板主题Runtime项目运行时目录包括Cache模板缓存、Temp数据缓存、Data数据目录和Logs日志文件子目录如果存在分组的话则首先是分组目录。 如果需要把index.php 移动到App目录的外面只需要在入口文件中增加项目名称和项目路径定义。?php    //定义项目名称    define(APP_NAME, App);    //定义项目路径    define(APP_PATH, ./App/);    //加载框架入文件    require ./App/ThinkPHP/ThinkPHP.php;APP_NAME 是指项目名称注意APP_NAME 不要随意设置通常是项目的目录名称如果你的项目是直接部署在Web根目录下面的话那么需要设置APP_NAME 为空。APP_PATH 是指项目路径必须以“/”结束项目路径是指项目的Common、Lib目录所在的位置而不是项目入口文件所在的位置。注意在类Unix或者Linux环境下面Runtime目录需要可写权限。 8. 部署目录 目录/文件说明ThinkPHP系统目录下面的目录结构同上面的系统目录Public网站公共资源目录存放网站的Css、Js和图片等资源Uploads网站上传目录用户上传的统一目录Home项目目录下面的目录结构同上面的应用目录Admin后台管理项目目录…… 更多的项目目录index.php项目Home的入口文件admin.php项目Admin的入口文件…… 更多的项目入口文件 项目的模板文件还是放到项目的Tpl目录下面只是将外部调用的资源文件 包括图片 JS 和CSS统一放到网站的公共目录Public下面分Images、Js和Css子目录存放如果有可能的话甚至也可以把这些资源文件单独放一个外部的服务器远程调用并进行优化。事实上系统目录和项目目录可以放到非WEB访问目录下面网站目录下面只需要放置Public公共目录和入口文件从而提高网站的安全性。   如果希望自己设置目录可以在入口文件里面更改RUNTIME_PATH常量进行更改例如define(RUNTIME_PATH,./App/temp/);注意RUNTIME_PATH目录必须设置为可写权限。除了自定义编译缓存目录之外还支持自定义编译缓存文件名例如define(RUNTIME_FILE,./App/temp/runtime_cache.php);ThinkPHP框架中所有配置文件的定义格式均采用返回PHP数组的方式格式为//项目配置文件 return array(    DEFAULT_MODULE      Index, //默认模块    URL_MODEL           2, //URL模式    SESSION_AUTO_START  true, //是否开启session    //更多配置参数    //... );配置参数不区分大小写因为无论大小写定义都会转换成小写 还可以在配置文件中可以使用二维数组来配置更多的信息例如//项目配置文件 return array(    DEFAULT_MODULE      Index, //默认模块    URL_MODEL           2, //URL模式    SESSION_AUTO_START  true, //是否开启session    USER_CONFIG         array(        USER_AUTH  true,        USER_TYPE  2,    ),    //更多配置参数    //... );需要注意的是二级参数配置区分大小写也就说读取确保和定义一致。 9. 惯例配置和项目配置调试配置 惯例重于配置是系统遵循的一个重要思想系统内置有一个惯例配置文件位于系统目录下面的Conf\convention.php按照大多数的使用对常用参数进行了默认配置。 项目配置文件是最常用的配置文件项目配置文件位于项目的配置文件目录Conf下面文件名是config.php。在项目配置文件里面除了添加内置的参数配置外还可以额外添加项目需要的配置参数。 如果没有配置应用状态系统默认则默认为debug状态也就是说默认的配置参数是APP_STATUS  debug, //应用调试模式状态debug.php配置文件只需要配置和项目配置文件以及系统调试配置文件不同的参数或者新增的参数。如果想在调试模式下面增加应用状态例如测试状态则可以在项目配置文件中改变设置如下APP_STATUS  test, //应用调试模式状态由于调试模式没有任何缓存因此涉及到较多的文件IO操作和模板实时编译所以在开启调试模式的情况下性能会有一定的下降但不会影响部署模式的性能。注意一旦关闭调试模式项目的调试配置文件即刻失效。 10. 分组配置和读取配置动态配置 如果启用了模块分组则可以在对每个分组单独定义配置文件分组配置文件位于项目配置目录/分组名称/config.php可以通过如下配置启用分组APP_GROUP_LIST  Home,Admin, //项目分组设定 DEFAULT_GROUP   Home, //默认分组现在定义了Home和Admin两个分组则我们可以定义分组配置文件如下Conf/Home/config.phpConf/Admin/config.php每个分组的配置文件仅在当前分组有效分组配置的定义格式和项目配置是一样的。注意分组名称区分大小写必须和定义的分组名一致。 定义了配置文件之后可以使用系统提供的C方法如果觉得比较奇怪的话可以借助Config单词来帮助记忆来读取已有的配置C(参数名称)//获取已经设置的参数值例如C(APP_STATUS) 可以读取到系统的调试模式的设置值如果APP_STATUS尚未存在设置则返回NULL。 C方法同样可以用于读取二维配置C(USER_CONFIG.USER_TYPE)//获取用户配置中的用户类型设置因为配置参数是全局有效的因此C方法可以在任何地方读取任何配置哪怕某个设置参数已经生效过期了。 在具体的Action方法里面我们仍然可以对某些参数进行动态配置主要是指那些还没有被使用的参数。 设置新的值C(参数名称,新的参数值);例如我们需要动态改变数据缓存的有效期的话可以使用C(DATA_CACHE_TIME,60);也可以支持二维数组的读取和设置使用点语法进行操作如下获取已经设置的参数值C(USER_CONFIG.USER_TYPE);设置新的值C(USER_CONFIG.USER_TYPE,1);3.1版本开始C函数支持配置保存功能仅对批量设置有效使用方法C($array,name);其中array是一个数组变量会把批量设置后的配置参数列表保存到name标识的缓存数据中获取缓存的设置列表数据 可以用C(,name); //或者C(null,name);会读取name标识的缓存配置数据到当前配置数据合并。 11. 扩展配置 项目配置文件在部署模式的时候会纳入编译缓存也就是说编译后再修改项目配置文件就不会立刻生效需要删除编译缓存后才能生效。扩展配置文件则不受此限制影响即使在部署模式下面修改配置后可以实时生效并且配置格式和项目配置一样。设置扩展配置的方式如下多个文件用逗号分隔LOAD_EXT_CONFIG  user,db, // 加载扩展配置文件项目设置了加载扩展配置文件user.php 和db.php分别用于用户配置和数据库配置那么会自动加载项目配置目录下面的配置文件Conf/user.php和Conf/db.php。 如果希望采用二级配置方式可以设置如下LOAD_EXT_CONFIG  array(    USER  user, //用户配置    DB    db, //数据库配置 ), //加载扩展配置文件同样的user.php 配置文件内容但最终获取用户参数的方式就变成了C(USER.USER_AUTH_ID);这种方式可以避免大项目情况中的参数冲突问题。 下面的一些配置文件已经被系统使用请不要作为自定义的扩展配置重新定义 文件名说明config.php项目配置文件tags.php项目行为配置文件alias.php项目别名定义文件debug.php项目调试模式配置文件以及项目设置的APP_STATUS对应的配置文件core.php项目追加的核心编译列表文件不会覆盖核心编译列表12. 函数库 ThinkPHP中的函数库可以分为系统函数库和项目函数库。 系统函数库 库系统函数库位于系统的Common目录下面有三个文件common.php是全局必须加载的基础函数库在任何时候都可以直接调用functions.php是框架标准模式的公共函数库其他模式可以替换加载自己的公共函数库或者对公共函数库中的函数进行重新定义runtime.php是框架运行时文件仅在调试模式或者编译过程才会被加载因此其中的方法在项目中不能直接调用 项目函数库 库项目函数库通常位于项目的Common目录下面文件名为common.php该文件会在执行过程中自动加载并且合并到项目编译统一缓存如果使用了分组部署方式并且该目录下存在分组名称/function.php文件也会根据当前分组执行时对应进行自动加载因此项目函数库的所有函数也都可以无需手动载入而直接使用。如果项目配置中使用了动态函数加载配置的话项目Common目录下面可能会存在更多的函数文件动态加载的函数文件不会纳入编译缓存。在特殊的情况下模式可以改变自动加载的项目函数库的位置或者名称。 扩展函数库 库我们可以在项目公共目录下面定义扩展函数库方便需要的时候加载和调用。扩展函数库的函数定义规范和项目函数库一致只是函数库文件名可以随意命名一般来说扩展函数库并不会自动加载除非你设置了动态载入。 函数加载 系统函数库和项目函数库中的函数无需加载就可以直接调用对于项目的扩展函数库可以采用下面两种方式调用动态载入我们可以在项目配置文件中定义LOAD_EXT_FILE参数例如LOAD_EXT_FILEuser,db通过上面的设置就会执行过程中自动载入项目公共目录下面的扩展函数库文件user.php和db.php这样就可以直接在项目中调用扩展函数库user.php和db.php中的函数了而且扩展函数库的函数修改是实时生效的。手动载入如果你的函数只是个别模块偶尔使用则不需要采用自动加载方式可以在需要调用的时候采用load方法手动载入方式如下load(.user).user表示加载当前项目的user函数文件这样就可以直接user.php扩展函数库中的函数了。 13. 类库 ThinkPHP的类库包括基类库和应用类库系统的类库命名规则如下 类库规则示例控制器类模块名Action例如 UserAction、InfoAction模型类模型名Model例如 UserModel、InfoModel行为类行为名Behavior例如CheckRouteBehaviorWidget类Widget名Widget例如BlogInfoWidget驱动类引擎名驱动名例如DbMysql表示mysql数据库驱动、CacheFile表示文件缓存驱动基类库 基类库是指符合ThinkPHP类库规范的系统类库包括ThinkPHP的核心基类库和扩展基类库。核心基类库目录位于系统的Lib目录核心基类库也就是Think类库扩展基类库位于Extend/Library目录可以扩展ORG 、Com扩展类库。核心基类库的作用是完成框架的通用性开发而必须的基础类和内置支持类等包含有 目录调用路径说明Lib/CoreThink.Core核心类库包Lib/BehaviorThink.Behavior内置行为类库包Lib/DriverThink.Driver内置驱动类库包Lib/TemplateThink.Template内置模板引擎类库包 核心类库包下面包含下面核心类库 类名说明Action系统基础控制器类App系统应用类Behavior系统行为基础类Cache系统缓存类Db系统抽象数据库类DispatcherURL调度类Log系统日志类Model系统基础模型类Think系统入口和静态类ThinkException系统基础异常类View视图类Widget系统Widget基础类应用类库 应用类库是指项目中自己定义或者使用的类库这些类库也是遵循ThinkPHP的命名规范。应用类库目录位于项目目录下面的Lib目录。应用类库的范围很广包括Action类库、Model类库或者其他的工具类库通常包括 目录调用路径说明Lib/Action.Action或自动加载控制器类库包Lib/Model.Model或自动加载模型类库包Lib/Behavior用B方法调用或自动加载应用行为类库包Lib/Widget用W方法在模板中调用应用Widget类库包 项目根据自己的需要可以在项目类库目录下面添加自己的类库包例如Lib/Common、Lib/Tool等。 类库导入 一、Import显式导入 ThinkPHP模拟了Java的类库导入机制统一采用import方法进行类文件的加载。import方法是ThinkPHP内建的类库导入方法提供了方便和灵活的文件导入机制完全可以替代PHP的require和include方法。例如import(Think.Util.Session); import(App.Model.UserModel);import方法具有缓存和检测机制相同的文件不会重复导入如果导入了不同的位置下面的同名类库文件系统也不会再次导入 注意在Unix或者Linux主机下面是区别大小写的所以在使用import方法的时候要注意目录名和类库名称的大小写否则会导入失败。对于import方法系统会自动识别导入类库文件的位置ThinkPHP的约定是Think、ORG、Com包的导入作为基类库导入否则就认为是项目应用类库导入。 import(Think.Util.Session); import(ORG.Util.Page);上面两个方法分别导入了Think基类库的Util/Session.class.php文件和ORG扩展类库包的Util/Page.class.php文件。 要导入项目的应用类库文件也很简单使用下面的方式就可以了和导入基类库的方式看起来差不多import(MyApp.Action.UserAction); import(MyApp.Model.InfoModel);上面的方式分别表示导入MyApp项目下面的Lib/Action/UserAction.class.php和Lib/Model/InfoModel.class.php类文件。 通常我们都是在当前项目里面导入所需的类库文件所以我们可以使用下面的方式来简化代码import(.Action.UserAction); import(.Model.InfoModel); 二别名导入 除了命名空间的导入方式外import方法还可以支持别名导入要使用别名导入首先要定义别名我们可以在项目配置目录下面增加alias.php 用以定义项目中需要用到的类库别名例如return array(    rbac LIB_PATH.Common/Rbac.class.php,    page LIB_PATH.Common/Page.class.php, );那么现在就可以直接使用import(rbac); import(page);导入Rbac和Page类别名导入方式禁止使用import方法的第二和第三个参数别名导入方式的效率比命名空间导入方式要高效缺点是需要预先定义相关别名。 导入第三方类库 第三方类库统一放置在系统扩展目录下的Vendor 目录并且使用vendor 方法导入其参数和 import 方法是 一致的只是默认的值有针对变化。 例如我们把 Zend 的 Filter\Dir.php 放到 Vendor 目录下面这个时候 Dir 文件的路径就是  Vendor\Zend\Filter\Dir.php我们使用vendor 方法导入只需要使用Vendor(Zend.Filter.Dir);就可以导入Dir类库了。Vendor方法也可以支持和import方法一样的基础路径和文件名后缀参数例如Vendor(Zend.Filter.Dir,dirname(__FILE__),.class.php); 自动加载 在大多数情况下我们无需手动导入类库而是通过配置采用自动加载机制即可自动加载机制是真正的按需加载可以很大程度的提高性能。自动加载有三种情况按照加载优先级从高到低分别是别名自动加载、系统规则自动加载和自定义路径自动加载。 一、别名自动加载 在前面我们提到了别名的定义方式并且采用了import方法进行别名导入其实所有定义别名的类库都无需再手动加载系统会按需自动加载。 二、 系统规则自动加载 果你没有定义别名的话系统会首先按照内置的规则来判断加载系统规则仅针对行为类、模型类和控制器类搜索规则如下 类名规则说明行为类规则1搜索系统类库目录下面的Behavior目录规则2搜索系统扩展目录下面的Behavior目录规则3搜索应用类库目录下面的Behavior目录规则4如果启用了模式扩展则搜索模式扩展目录下面的Behavior目录模型类规则1如果启用分组则搜索应用类库目录的Model/当前分组 目录规则2搜索应用类库下面的Model目录规则3搜索系统扩展目录下面的Model目录控制器类规则1如果启用分组则搜索应用类库目录的Action/当前分组 目录规则2搜索项目类库目录下面的Action目录规则3搜索系统扩展目录下面的Action目录 注意搜索的优先顺序从上至下 一旦找到则返回后面规则不再检测。如果全部规则检测完成后依然没有找到类库则开始进行第三个自定义路径自动加载检测。 三、 自定义路径自动加载 当你的类库比较集中在某个目录下面而且不想定义太多的别名导入的话可以使用自定义路径自动加载方式这种方式需要在项目配置文件中添加自动加载的搜索路径例如APP_AUTOLOAD_PATH .Common,.Tool,表示在当前项目类库目录下面的Common和Tool目录下面的类库可以自动加载。多个搜索路径之间用逗号分割并且注意定义的顺序也就是自动搜索的顺序。注意自动搜索路径定义只能采用命名空间方式也就是说这种方式只能自动加载项目类库目录和基类库目录下面的类库文件。 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 控制器 1. URL模式 传统方式的文件入口访问会变成由URL的参数来统一解析和调度。 ThinkPHP支持四种URL模式可以通过设置URL_MODEL参数来定义包括普通模式、PATHINFO、REWRITE和兼容模式。 一、普通模式设置URL_MODEL 为0采用传统的URL参数模式http://serverName/appName/?mmoduleaactionid1 二、PATHINFO模式默认模式设置URL_MODEL 为1默认情况使用PATHINFO模式ThinkPHP内置强大的PATHINFO支持提供灵活和友好URL支持。PATHINFO模式自动识别模块和操作例如http://serverName/appName/module/action/id/1/或者http://serverName/appName/module,action,id,1/ 三、REWRITE模式 设置URL_MODEL 为2该URL模式和PATHINFO模式功能一样除了可以不需要在URL里面写入口文件和可以定义.htaccess 文件外。在开启了Apache的URL_REWRITE模块后就可以启用REWRITE模式了具体参考下面的URL重写部分。 四、兼容模式 设置URL_MODEL 为3兼容模式是普通模式和PATHINFO模式的结合并且可以让应用在需要的时候直接切换到PATHINFO模式而不需要更改模板和程序还可以和URL_WRITE模式整合。兼容模式URL可以支持任何的运行环境。 兼容模式的效果是http://serverName/appName/?s/module/action/id/1/并且也可以支持参数分割符号的定义例如在URL_PATHINFO_DEPR为~的情况下下面的URL有效http://serverName/appName/?smodule~action~id~1其实是利用了VAR_PATHINFO参数用普通模式的实现模拟了PATHINFO的模式。但是兼容模式并不需要自己传s变量而是由系统自动完成URL部分。正是由于这个特性兼容模式可以和PATHINFO模式之间直接切换而不需更改模板文件里面的URL地址连接。我们建议的方式是采用PATHINFO模式开发如果部署的时候环境不支持PATHINFO则改成兼容URL模式部署即可程序和模板都不需要做任何改动。 2. 模块和操作 http://域名/项目名/分组名/模块名/操作名/其他参数Dispatcher会根据URL地址来获取当前需要执行的项目、分组如果有定义的话模块、操作以及其他参数在某些情况下项目名可能不会出现在URL地址中通常情况下入口文件则代表了某个项目而且入口文件可以被隐藏。每一个模块就是一个控制器类通常位于项目的Lib\Action目录下面。 3.1版本开始增加ACTION_SUFFIX配置参数用于设置操作方法的后缀。例如如果设置ACTION_SUFFIXAct那么访问某个模块的add操作对应读取模块类的操作方法则由原来的add方法变成addAct方法。 3. 定义控制器和空操作空模块 一个应用如果不需要和数据库交互的时候可以不需要定义模型类但是必须定义Action控制器一般位于项目的Lib/Action目录下面。Action控制器的定义非常简单只要继承Action基础类就可以了例如Class UserAction extends Action{}控制器文件的名称是UserAction.class.php。 空操作是指系统在找不到指定的操作方法的时候会定位到空操作_empty方法来执行利用这个机制我们可以实现错误页面和一些URL的优化。 空模块的概念是指当系统找不到指定的模块名称的时候系统会尝试定位空模块(EmptyAction)利用这个机制我们可以用来定制错误页面和进行URL的优化。 4. 模块分组 模块分组相关的配置参数包括 配置参数说明APP_GROUP_LIST项目分组列表配置即表示开启分组DEFAULT_GROUP默认分组默认值为HomeTMPL_FILE_DEPR分组模板下面模块和操作的分隔符默认值为“/”VAR_GROUP分组的URL参数名默认为g普通模式URL才需要 例如我们把当前的项目分成Home和Admin两个组分别表示前台和后台功能那么只需要在项目配置中添加下面的配置APP_GROUP_LIST  Home,Admin, //项目分组设定 DEFAULT_GROUP   Home, //默认分组多个分组之间用逗号分隔即可默认分组只允许设置一个。 5. URL伪静态 ThinkPHP支持伪静态URL设置可以通过设置URL_HTML_SUFFIX参数随意在URL的最后增加你想要的静态后缀而不会影响当前操作的正常执行。例如我们设置URL_HTML_SUFFIXshtml的话我们可以把下面的URLhttp://serverName/Blog/read/id/1变成http://serverName/Blog/read/id/1.shtml后者更具有静态页面的URL特征但是具有和前面的URL相同的执行效果并且不会影响原来参数的使用。注意伪静态后缀设置时可以不包含后缀中的“.”。所以下面的配置其实是等效的URL_HTML_SUFFIX.shtml伪静态设置后如果需要动态生成一致的URL可以使用U方法在模板文件里面生成URL。 3.1版本开始默认情况下可以支持所有的静态后缀并且会记录当前的伪静态后缀到常量__EXT__但不会影响正常的页面访问。如果要获取当前的伪静态后缀通过常量__EXT__获取即可。 如果只是希望支持配置的伪静态后缀可以直接设置成可以支持多个后缀例如URL_HTML_SUFFIXhtml|shmtl|xml // 多个用 | 分割如果设置了多个伪静态后缀的话使用U函数生成的URL地址中会默认使用第一个后缀也支持指定后缀生成url地址。 6. URL路由 ThinkPHP支持URL路由功能要启用路由功能需要设置URL_ROUTER_ON 参数为true。开启路由功能后并且配置URL_ROUTE_RULES参数后系统会自动进行路由检测如果在路由定义里面找到和当前URL匹配的路由名称就会进行路由解析和重定向。 详情见http://doc.thinkphp.cn/manual/url_route.html 7. URL重写 详情见http://doc.thinkphp.cn/manual/url_rewrite.html 8. URL生成 为了配合所使用的URL模式我们需要能够动态的根据当前的URL设置生成对应的URL地址为此ThinkPHP内置提供了U方法用于URL的动态生成可以确保项目在移植过程中不受环境的影响。U方法的定义规则如下方括号内参数根据实际应用决定U([分组/模块/操作]?参数 [,参数,伪静态后缀,是否跳转,显示域名])如果不定义项目和模块的话 就表示当前项目和模块名称下面是一些简单的例子U(User/add) // 生成User模块的add操作的URL地址U(Blog/read?id1) // 生成Blog模块的read操作 并且id为1的URL地址U(Admin/User/select) // 生成Admin分组的User模块的select操作的URL地址U方法的第二个参数支持数组和字符串两种定义方式如果只是字符串方式的参数可以在第一个参数中定义例如U(Blog/cate,array(cate_id1,status1))U(Blog/cate,cate_id1status1)U(Blog/cate?cate_id1status1)三种方式是等效的都是 生成Blog模块的cate操作 并且cate_id为1 status为1的URL地址但是不允许使用下面的定义方式来传参数U(Blog/cate/cate_id/1/status/1) 根据项目的不同URL设置同样的U方法调用可以智能地对应产生不同的URL地址效果例如针对UBlog/read?id1这个定义为例。如果当前URL设置为普通模式的话最后生成的URL地址是 http://serverName/index.php?mBlogareadid1如果当前URL设置为PATHINFO模式的话同样的方法最后生成的URL地址是 http://serverName/index.php/Blog/read/id/1如果当前URL设置为REWRITE模式的话同样的方法最后生成的URL地址是 http://serverName/Blog/read/id/1如果当前URL设置为REWRITE模式并且设置了伪静态后缀为.html的话同样的方法最后生成的URL地址是 http://serverName/Blog/read/id/1.htmlU方法还可以支持路由如果我们定义了一个路由规则为 news/:id\dNews/read那么可以使用U/news/1最终生成的URL地址是http://serverName/index.php/news/1注意如果你是在模板文件中直接使用U方法的话需要采用 {:U(参数1, 参数2…)} 的方式具体参考模板引擎章节的8.3 使用函数内容。 如果你的应用涉及到多个子域名的操作地址那么也可以在U方法里面指定需要生成地址的域名例如 U(Blog/readblog.thinkphp.cn,id1);后面传入需要指定的域名即可。此外U方法的第5个参数如果设置为true表示自动识别当前的域名并且会自动根据子域名部署设置APP_SUB_DOMAIN_DEPLOY和APP_SUB_DOMAIN_RULES自动匹配生成当前地址的子域名。如果开启了URL_CASE_INSENSITIVE则会统一生成小写的URL地址。   9. URL大小写 只要在项目配置中增加   URL_CASE_INSENSITIVE true就可以实现URL访问不再区分大小写了。 这里需要注意一个地方如果我们定义了一个UserTypeAction的模块类那么URL的访问应该是 http://serverName/index.php/user_type/list //而不是http://serverName/index.php/usertype/list利用系统提供的U方法可以为你自动生成相关的URL地址。如果设置 URL_CASE_INSENSITIVE false的话URL就又变成 http://serverName/index.php/UserType/list注意URL不区分大小写并不会改变系统的命名规范并且只有按照系统的命名规范后才能正确的实现URL不区分大小写。   10. 前置和后置操作 系统会检测当前操作是否具有前置和后置操作如果存在就会按照顺序执行前置和后置操作的方法名是在要执行的方法前面加 _before_和_after_例如   class CityAction extends Action{    //前置操作方法    public function _before_index(){        echo beforebr/;    }    public function index(){        echo indexbr/;    }    //后置操作方法    public function _after_index(){        echo afterbr/;    } }对于任何操作方法我们都可以按照这样的规则来定义前置和后置方法。 如果当前的操作并没有定义操作方法而是直接渲染模板文件那么如果定义了前置 和后置方法的话依然会生效。真正有模板输出的可能仅仅是当前的操作前置和后置操作一般情况是没有任何输出的。需要注意的是在有些方法里面使用了exit或者错误输出之类的话 有可能不会再执行后置方法了。例如如果在当前操作里面调用了系统Action的error方法那么将不会再执行后置操作但是不影响success方法的后置方法执行。 11. 跨模块调用 例如我们在Index模块调用User模块的操作方法class IndexAction extends Action{    public function index(){        //实例化UserAction        $User  new UserAction();        //其他用户操作         //...        $this-display(); //输出页面模板    } } 因为系统会自动加载Action控制器因此 我们不需要导入UserAction类就可以直接实例化。并且为了方便跨模块调用系统内置了A方法和R方法。    $User  A(User); 事实上A方法还支持跨分组或者跨项目调用默认情况下是调用当前项目下面的模块。跨项目调用的格式是A([项目名://][分组名/]模块名)例如A(User) //表示调用当前项目的User模块A(Admin://User) //表示调用Admin项目的User模块A(Admin/User) //表示调用Admin分组的User模块A(Admin://Tool/User) //表示调用Admin项目Tool分组的User模块 R方法表示调用一个模块的某个操作方法调用格式是R([项目名://][分组名/]模块名/操作名,array(参数1,参数2…))例如R(User/info) //表示调用当前项目的User模块的info操作方法R(Admin/User/info) //表示调用Admin分组的User模块的info操作方法R(Admin://Tool/User/info) //表示调用Admin项目Tool分组的User模块的info操作方法R方法还支持对调用的操作方法需要传入参数例如User模块中我们定义了一个info方法class UserAction extends Action{    protected function info($id){        $User  M(User);        $User-find($id);        //...    } }接下来我们可以在其他模块中调用R(User/info,array(15))表示调用当前项目的User模块的info操作方法并且id参数传入15 12. 页面跳转 系统的Action类内置了两个跳转方法success和error用于页面跳转提示而且可以支持ajax提交。使用方法很简单举例如下$User  M(User); //实例化User对象$result  $User-add($data); if($result){    //设置成功后跳转页面的地址默认的返回页面是$_SERVER[HTTP_REFERER]    $this-success(新增成功, User/list);} else {    //错误页面的默认跳转页面是返回前一页通常不需要设置    $this-error(新增失败);} Success和error方法都有对应的模板并且是可以设置的默认的设置是两个方法对应的模板都是//默认错误跳转对应的模板文件TMPL_ACTION_ERROR  THINK_PATH . Tpl/dispatch_jump.tpl;//默认成功跳转对应的模板文件TMPL_ACTION_SUCCESS  THINK_PATH . Tpl/dispatch_jump.tpl;也可以使用项目内部的模板文件//默认错误跳转对应的模板文件TMPL_ACTION_ERROR  Public:error;//默认成功跳转对应的模板文件TMPL_ACTION_SUCCESS  Public:success;模板文件可以使用模板标签并且可以使用下面的模板变量 $msgTitle操作标题$message页面提示信息$status操作状态 1表示成功 0 表示失败 具体还可以由项目本身定义规则$waitSecond跳转等待时间 单位为秒$jumpUrl跳转页面地址 success和error方法会自动判断当前请求是否属于Ajax请求如果属于Ajax请求则会调用ajaxReturn方法返回信息具体可以参考后面的AJAX返回部分。 3.1版本开始error和success方法支持传值无论是跳转模板方式还是ajax方式 都可以使用assign方式传参。例如$this-assign(var1,value1);$this-assign(var2,value2);$this-error(错误的参数,要跳转的URL地址);当正常方式提交的时候var1和var2变量会赋值到错误模板的模板变量。当采用AJAX方式提交的时候会自动调用ajaxReturn方法传值过去包括跳转的URL地址url和状态值status 13. 重定向 Action类的redirect方法可以实现页面的重定向功能。redirect方法的参数用法和U函数的用法一致参考上面的URL生成部分例如//重定向到New模块的Category操作$this-redirect(New/category, array(cate_id  2), 5, 页面跳转中...);上面的用法是停留5秒后跳转到News模块的category操作并且显示页面跳转中字样重定向后会改变当前的URL地址。如果你仅仅是想重定向要一个指定的URL地址而不是到某个模块的操作方法可以直接使用redirect方法重定向例如//重定向到指定的URL地址redirect(/New/category/cate_id/2, 5, 页面跳转中...)Redirect方法的第一个参数是一个URL地址。 14. 获取系统变量 $this-方法名(变量名,[过滤方法],[默认值]) 方法名可以支持 方法名含义_get获取GET参数_post获取POST参数_param自动判断请求类型获取GET、POST或者PUT参数3.1新增_request获取REQUEST 参数_put获取PUT 参数_session获取 $_SESSION 参数_cookie获取 $_COOKIE 参数_server获取 $_SERVER 参数_globals获取 $GLOBALS参数变量名必须是要获取的系统变量的名称过滤方法可选可以用任何的内置函数或者自定义函数名如果没有指定的话采用默认的htmlspecialchars函数进行安全过滤由DEFAULT_FILTER 参数配置参数就是前面方法名获取到的值也就是说如果调用$this-_get(name);最终调用的结果就是 htmlspecialchars($_GET[name])如果要改变过滤方法可以使用$this-_get(name,strip_tags);默认值可选是要获取的参数变量不存在的情况下设置的默认值例如$this-_get(id,strip_tags,0);如果$_GET[id] 不存在的话会返回0。 如果没有设置任何默认值的话系统默认返回NULL。 也可以支持多函数过滤。例如可以设置  DEFAULT_FILTERhtmlspecialchars,strip_tags 那么在控制器类如果调用 $this-_get(id); 的话会依次对$_GET[id] 变量进行htmlspecialchars和strip_tags方法过滤后返回结果。下面调用方式也同样支持 $this-_get(id,htmlspecialchars,strip_tags,0); 其他变量获取方法用法相同。支持获取全部变量例如 $this-_get(); 表示获取$_GET变量值。 支持不过滤处理 如果不希望过滤某个参数可以使用 $this-_get(id,false);$this-_post(id,false); //或者$this-_get(id,);$this-_post(id,); 第二个参数使用false或者空字符串则表示不作任何过滤处理即使我们有配置默认的过滤方法。如果我们忽略第二个参数调用的话 $this-_get(id);$this-_post(id); 则表示调用默认的过滤方法由DEFAULT_FILTER参数进行配置。 3.1版本开始Action类增加_param方法可以自动根据当前请求类型例如GET POST)获取参数。例如 $this-_param(id); 当前为get方式提交的时候就是获取$_GET[id]进行默认过滤后的值当前为post方式提交的时候就是获取$_POST[id]进行默认过滤后的值还可以用_param方法获取URL中的参数 $this-_param(0); // 获取PATHINFO地址中的第一个参数$this-_param(2); // 获取PATHINFO地址中的第3个参数 15. 判断请求类型 系统Action类内置了一些判断方法用于判断请求类型包括 方法说明isGet判断是否是GET方式提交isPost判断是否是POST方式提交isPut判断是否是PUT方式提交isDelete判断是否是DELETE方式提交isHead判断是否是HEAD提交使用举例如下class UserAction extends Action{    public function update(){        if ($this-isPost()){            $User  M(User);            $User-create();            $User-save();            $this-success(保存完成);        }else{            $this-error(非法请求);        }    } } 另外还提供了一个判断当前是否属于AJAX提交的方法isAjax 是否属于AJAX提交需要注意的是如果使用的是ThinkAjax或者自己写的Ajax类库的话需要在表单里面添加一个隐藏域告诉后台属于ajax方式提交默认的隐藏域名称是ajax可以通过VAR_AJAX_SUBMIT配置如果是JQUERY类库的话则无需添加任何隐藏域即可自动判断。 16. 获取URL参数 我们可以把URL地址 News/archive/2012/01/15 按照“/”分成多个参数$_GET[_URL_][0] 获取的就是News$_GET[_URL_][1]获取的就是archive依次类推可以通过数字索引获取所有的URL参数。 3.0版开始支持URL地址中的PATH_INFO方式的URL的参数获取方式需要配置VAR_URL_PARAMS参数默认值是    VAR_URL_PARAMS       _URL_, // PATHINFO URL参数变量如果这个值不为空的话就可以获取URL地址里面的PATH_INFO URL参数例如我们访问http://serverName.com/index.php/Blog/read/2012/03则可以在Blog控制器的read操作方法里面采用 $GET[_URL_][2] 获取参数表示获取PATH_INFO的URL参数Blog/read/2012/03中的第3个参数数组索引从0开始$year  $GET[_URL_][2]; // 2012$month  $GET[_URL_][3]; //  033.1版本开始建议使用_param方法获取URL参数_param方法方法是3.1新增的方法可以自动根据当前请求类型获取参数。_param方法的用法同_get和_post等方法区别在于_param方法能够自动根据当前请求类型自动获取相应的参数例如如果当前是get请求方式$this-_param(id); 将会返回$_GET[id] 的处理数据当采用POST请求方式的时候同样的代码将会返回$_POST[id]的处理数据如果采用的是PUT请求那么会自动返回PUT的处理数据而无需开发人员进行判断。并且需要注意的是无论是什么方式的请求系统都可以支持URL参数的获取如果C(VAR_URL_PARAMS)设置不为空的话就可以使用$this-_param(1);$this-_param(2);来获取URL地址中的某个参数。$year  $this-_param(2);$month  $this-_param(3);的方式来获取。这样的好处是可以不需要使用路由功能就可以获取某个不规则的URL地址中的参数。 17. AJAX返回 系统支持任何的AJAX类库Action类提供了ajaxReturn方法用于AJAX调用后返回数据给客户端。并且支持JSON、XML和EVAL三种方式给客户端接受数据通过配置DEFAULT_AJAX_RETURN进行设置默认配置采用JSON格式返回数据在选择不同的AJAX类库的时候可以使用不同的方式返回数据。要使用ThinkPHP的ajaxReturn方法返回数据的话需要遵守一定的返回数据的格式规范。 ThinkPHP返回的数据格式包括 status操作状态info提示信息data返回数据 调用示例$this-ajaxReturn(返回数据,提示信息,操作状态);返回数据data可以支持字符串、数字和数组、对象返回客户端的时候根据不同的返回格式进行编码后传输。如果是JSON格式会自动编码成JSON字符串如果是XML方式会自动编码成XML字符串如果是EVAL方式的话只会输出字符串data数据并且忽略status和info信息。 $User  M(User); // 实例化User对象$result  $User-add($data); if ($result){    // 成功后返回客户端新增的用户ID并返回提示信息和操作状态    $this-ajaxReturn($result,新增成功,1); }else{    // 错误后返回错误的操作状态和提示信息    $this-ajaxReturn(0,新增错误,0); }注意确保你是使用AJAX提交才使用ajaxReturn方法。在客户端接受数据的时候根据使用的编码格式进行解析即可。 如果需要改变Ajax返回的数据格式可以在控制器Action中增加ajaxAssign方法定义定义格式如下public function ajaxAssign($result) {    // 返回数据中增加url属性    $result[url]  $this-url; } 3.1版本以后ajaxReturn方法可以更加灵活的进行ajax传值并且废弃了ajaxAssign方法扩展。能够完全定义传值的数组和类型例如$data[status]  1;$data[info]  info;$data[size]  9;$data[url]  $url;$this-ajaxReturn($data,JSON);data传值数组可以随意定义。改进后的ajaxReturn方法也兼容之前的写法$this-ajaxReturn($data,info,1);系统会自动把info和1两个参数并入$data数组中等同于赋值$data[info]  info;$data[status]  1; 18. Action参数绑定 http://doc.thinkphp.cn/manual/action_param_bind.html 19. 多层控制器支持 3.1版本开始控制器支持自定义分层。同时A方法增加第二个参数layer用于设置控制器分层。例如A(User,Event);表示实例化Lib/Event/UserEvent.class.php。UserEvent如果继承Action类的话可以使用Action类所有的功能。A(User,Api);表示实例化Lib/Api/UserApi.class.php分层控制器仅用于内部调用URL访问的控制器还是Action层但是可以配置DEFAULT_C_LAYER修改默认控制器层名称该参数默认值为Action。 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 模型 模型类的命名规则是除去表前缀的数据表名称采用驼峰法命名并且首字母大写然后加上模型类的后缀定义Model例如 模型名类名约定对应数据表假设数据库的前缀定义是 think_UserModelthink_userUserTypeModelthink_user_type 如果你的规则和上面的系统约定不符合那么需要设置Model类的数据表名称属性。 在ThinkPHP的模型里面有几个关于数据表名称的属性定义属性说明tableName不包含表前缀的数据表名称一般情况下默认和模型名称相同只有当你的表名和当前的模型类的名称不同的时候才需要定义。trueTableName包含前缀的数据表名称也就是数据库中的实际表名该名称无需设置只有当上面的规则都不适用的情况或者特殊情况下才需要设置。dbName定义模型当前对应的数据库名称只有当你当前的模型类对应的数据库名称和配置文件不同的时候才需要定义。1. 模型实例化 在ThinkPHP中可以无需进行任何模型定义。只有在需要封装单独的业务逻辑的时候模型类才是必须被定义的。 1、实例化基础模型Model 类在没有定义任何模型的时候我们可以使用下面的方法实例化一个模型类来进行操作//实例化User模型$User  new Model(User); //或者使用M()快捷方法实例化和上面的方法是等效的$User  M(User); //执行其他的数据操作$User-select();这种方法最简单高效因为不需要定义任何的模型类所以支持跨项目调用。缺点也是因为没有自定义的模型类因此无法写入相关的业务逻辑只能完成基本的CURD操作。 2、实例化其他公共模型类 $User  new CommonModel(User);模型类的实例化方法有三个参数第一个参数是模型名称第二个参数用于设置数据表的前缀留空则取当前项目配置的表前缀第三个参数用于设置当前使用的数据库连接信息留空则取当前项目配置的数据库连接信息例如$User  new CommonModel(User,think_,db_config); 用M方法实现的话上面的方法可以写成$User  M(CommonModel:User,think_,db_config);M方法默认是实例化Model类第二个参数用于指定表前缀第三个参数就可以指定其他的数据库连接信息。 模型类CommonModel必须继承Model。我们可以在CommonModel类里面定义一些通用的逻辑方法就可以省去为每个数据表定义具体的模型类。 3、实例化用户自定义模型×××Model类这种情况是使用的最多的一个项目不可避免的需要定义自身的业务逻辑实现就需要针对每个数据表定义一个模型类例如UserModel 、InfoModel等等。定义的模型类通常都是放到项目的Lib\Model目录下面。例如?php    class UserModel extends Model{        public function getTopUser(){            //添加自己的业务逻辑             // ...        }    }其实模型类还可以继承一个用户自定义的公共模型类而不是只能继承Model类。 要实例化自定义模型类可以使用下面的方式?php    //实例化自定义模型    $User  new UserModel();    //或者使用D快捷方法    $User  D(User);    //执行具体的数据操作    $User-select();D方法可以自动检测模型类如果存在自定义的模型类则实例化自定义模型类如果不存在则会实例化Model基类同时对于已实例化过的模型不会重复去实例化。 D方法还可以支持跨项目和分组调用需要使用//实例化Admin项目的User模型D(Admin://User) //实例化Admin分组的User模型D(Admin/User) 2. 字段定义 字段缓存保存在Runtime/Data/_fields/ 目录下面缓存机制是每个模型对应一个字段缓存文件而并非每个数据表对应一个字段缓存文件命名格式是数据库名.模型名.php 字段缓存包括数据表的字段信息、主键字段和是否自动增长如果开启字段类型验证的话还包括字段类型信息等等无论是用M方法还是D方法或者用原生的实例化模型类一般情况下只要是不开启调试模式都会生成字段缓存字段缓存可以单独设置关闭。从3.1版本开始模型的字段缓存文件名全部转换成小写避免重复生成。 可以通过设置DB_FIELDS_CACHE 参数来关闭字段自动缓存如果在开发的时候经常变动数据库的结构而不希望进行数据表的字段缓存可以在项目配置文件中增加如下配置DB_FIELDS_CACHEfalse注意调试模式下面由于考虑到数据结构可能会经常变动所以默认是关闭字段缓存的。 如果需要显式获取当前数据表的字段信息可以使用模型类的getDbFields方法来获取当前数据对象的全部字段信息例如$fields  $User-getDbFields(); 如果你在部署模式下面修改了数据表的字段信息可能需要清空Data/_fields目录下面的缓存文件让系统重新获取更新的数据表字段信息否则会发生新增的字段无法写入数据库的问题。 如果不希望依赖字段缓存或者想提高性能也可以在模型类里面手动定义数据表字段的名称可以避免IO加载的效率开销在模型类里面添加fields属性即可定义格式如下?php    class UserModel extends Model{        protected $fields  array(            id, username, email, age, _pk  id, _autoinc  true        );    } 3. 数据主键 ThinkPHP的默认约定每个数据表的主键名采用统一的id作为标识并且是自动增长类型的。系统会自动识别当前操作的数据表的字段信息和主键名称所以即使你的主键不是id也无需进行额外的设置系统会自动识别。要在外部获取当前数据对象的主键名称请使用下面的方法$pk  $Model-getPk();注意目前不支持联合主键的自动获取和操作。  4. 属性访问 ThinkPHP的模型对象实例本身也是一个数据对象可以支持对象和数组两种方式来访问数据属性例如下面的方式采用数据对象的方式来访问User模型的属性//实例化User模型$User  D(User); //查询用户数据$User-find(1); //获取name属性的值echo $User-name; //设置name属性的值$User-name  ThinkPHP; 除了find方法会产生数据对象属性外data方法和create方法也会产生数据对象例如$User  D(User);$User-create();echo $User-name; 还有一种属性的操作方式是通过返回数组的方式//实例化User模型$User  D(User); //查询用户数据$data  $User-find(1); //获取name属性的值echo $data[name]; //设置name属性的值$data[name]  ThinkPHP;两种方式的属性获取区别是一个是对象的属性一个是数组的索引开发人员可以根据自己的需要选择什么方式。 5. 跨库操作 ThinkPHP可以支持模型的同一数据库服务器的跨库操作跨库操作只需要简单配置一个模型所在的数据库名称即可例如假设UserModel对应的数据表在数据库user下面而InfoModel对应的数据表在数据库info下面那么我们只需要进行下面的设置即可。class UserModel extends Model {    protected $dbName  user; } class InfoModel extends Model {    protected $dbName  info; }在进行查询的时候系统能够自动添加当前模型所在的数据库名。$User  D(User); $User-select();echo $User-getLastSql(); // 输出的SQL语句为 select * from user.think_user 模型的表前缀取的是项目配置文件定义的数据表前缀如果跨库操作的时候表前缀不是统一的那么我们可以在模型里面单独定义表前缀例如protected $tablePrefix  other_;如果你没有定义模型类而是使用的M方法操作的话也可以支持跨库操作例如$User  M(user.User,other_); 表示实例化User模型连接的是user数据库的other_user表。 6. 连接数据库 ThinkPHP内置了抽象数据库访问层把不同的数据库操作封装起来我们只需要使用公共的Db类进行操作而无需针对不同的数据库写不同的代码和底层实现Db类会自动调用相应的数据库驱动来处理。如果应用需要使用数据库必须配置数据库连接信息数据库的配置文件有多种定义方式。 常用的配置方式是在项目配置文件中添加下面的参数?php    //项目配置文件    return array(        //数据库配置信息        DB_TYPE    mysql, // 数据库类型        DB_HOST    localhost, // 服务器地址        DB_NAME    thinkphp, // 数据库名        DB_USER    root, // 用户名        DB_PWD     , // 密码        DB_PORT    3306, // 端口        DB_PREFIX  think_, // 数据库表前缀         //其他项目配置参数        // ...    );或者采用如下配置DB_DSN  mysql://username:passwordlocalhost:3306/DbName 如果两种配置参数同时存在的话DB_DSN配置参数优先。注意如果要设置分布式数据库暂时不支持DB_DSN方式配置。 如果采用PDO驱动的话则必须首先配置DB_TYPE 为pdo然后还需要单独配置其他参数例如//PDO连接方式 DB_TYPE    pdo, // 数据库类型 DB_USER    root, // 用户名 DB_PWD     , // 密码 DB_PREFIX  think_, // 数据库表前缀  DB_DSN     mysql:hostlocalhost;dbnamethinkphp;charsetUTF-8注意PDO方式的DB_DSN配置格式有所区别根据不同的数据库类型设置有所不同。配置文件定义的数据库连接信息一般是系统默认采用的因为一般一个项目的数据库访问配置是相同的。该方法系统在连接数据库的时候会自动获取无需手动连接。可以对每个项目和不同的分组定义不同的数据库连接信息如果开启了调试模式的话还可以在不同的应用状态的配置文件里面定义独立的数据库配置信息。 第二种 在模型类里面定义connection属性如果在某个模型类里面定义了connection属性的话则实例化该自定义模型的时候会采用定义的数据库连接信息而不是配置文件中设置的默认连接信息通常用于某些数据表位于当前数据库连接之外的其它数据库例如//在模型里单独设置数据库连接信息 protected $connection  array(    db_type   mysql,    db_user   root,    db_pwd    1234,    db_host   localhost,    db_port   3306,    db_name   thinkphp );也可以采用DSN方式定义例如//或者使用DSN定义 protected $connection  mysql://root:1234localhost:3306/thinkphp; 如果我们已经在配置文件中配置了额外的数据库连接信息例如//数据库配置1 DB_CONFIG1  array(    db_type   mysql,    db_user   root,    db_pwd    1234,    db_host   localhost,    db_port   3306,    db_name   thinkphp ), //数据库配置2 DB_CONFIG2  mysql://root:1234localhost:3306/thinkphp;那么我们可以把模型类的属性定义改为//调用配置文件中的数据库配置1 protected $connection  DB_CONFIG1; //调用配置文件中的数据库配置2 protected $connection  DB_CONFIG2; 如果采用的是M方法实例化模型的话也可以支持传入不同的数据库连接信息例如$User  M(User,other_,mysql://root:1234localhost/demo); 表示实例化User模型连接的是demo数据库的other_user表采用的连接信息是第三个参数配置的。如果我们在项目配置文件中已经配置了DB_CONFIG2的话也可以采用$User  M(User,other_,DB_CONFIG2); 如果你的个别数据表没有定义任何前缀的话可以在前缀参数中传入NULL例如$User  M(User,Null,DB_CONFIG2); 表示实例化User模型连接的是demo数据库的user表。需要注意的是ThinkPHP的数据库连接的惰性的所以并不是在实例化的时候就连接数据库而是在有实际的数据操作的时候才会去连接数据库额外的情况是在系统第一次实例化模型的时候会自动连接数据库获取相关模型类对应的数据表的字段信息。 7. 切换数据库 只需要调用Model类的db方法用法Model-db(数据库编号,数据库配置); 数据库编号用数字格式对于已经调用过的数据库连接是不需要再传入数据库连接信息的系统会自动记录。对于默认的数据库连接内部的数据库编号是0因此为了避免冲突请不要再次定义数据库编号为0的数据库配置。数据库配置的定义方式和模型定义connection属性一样支持数组、字符串以及调用配置参数三种格式。Db方法调用后返回当前的模型实例直接可以继续进行模型的其他操作所以该方法可以在查询的过程中动态切换例如$this-db(1,mysql://root:123456localhost:3306/test)-query(查询SQL);该方法添加了一个编号为1的数据库连接并自动切换到当前的数据库连接。当第二次切换到相同的数据库的时候就不需要传入数据库连接信息了可以直接使用$this-db(1)-query(查询SQL);如果需要切换到默认的数据库连接只需要调用$this-db(0); 如果我们已经在项目配置中定义了其他的数据库连接信息例如//数据库配置1 DB_CONFIG1  array(    db_type   mysql,    db_user   root,    db_pwd    1234,    db_host   localhost,    db_port   3306,    db_name   thinkphp ), //数据库配置2 DB_CONFIG2  mysql://root:1234localhost:3306/thinkphp;我们就可以直接在db方法中调用配置进行连接了$this-db(1,DB_CONFIG1)-query(查询SQL);$this-db(2,DB_CONFIG2)-query(查询SQL);如果切换数据库之后数据表和当前不一致的话可以使用table方法指定要操作的数据表$this-db(1)-table(top_user)-find();我们也可以直接用M方法切换数据库例如M(User,think_,mysql://root:123456localhost:3306/test)-query(查询SQL);或者M(User,think_,DB_CONFIG1)-query(查询SQL); 8. 分布式数据库 ThinkPHP内置了分布式数据库的支持包括主从式数据库的读写分离但是分布式数据库必须是相同的数据库类型。配置DB_DEPLOY_TYPE 为1 可以采用分布式数据库支持。如果采用分布式数据库定义数据库配置信息的方式如下//在项目配置文件里面定义 return array(    //分布式数据库配置定义    DB_TYPE    mysql, //分布式数据库类型必须相同    DB_HOST    192.168.0.1,192.168.0.2,    DB_NAME    thinkphp, //如果相同可以不用定义多个    DB_USER    user1,user2,    DB_PWD     pwd1,pwd2,    DB_PORT    3306,    DB_PREFIX  think_,    //其他配置参数    // ... ); 连接的数据库个数取决于DB_HOST定义的数量所以即使是两个相同的IP也需要重复定义但是其他的参数如果存在相同的可以不用重复定义。 还可以设置分布式数据库的读写是否分离默认的情况下读写不分离也就是每台服务器都可以进行读写操作对于主从式数据库而言需要设置读写分离通过下面的设置就可以DB_RW_SEPARATEtrue,在读写分离的情况下默认第一个数据库配置是主服务器的配置信息负责写入数据如果设置了DB_MASTER_NUM参数则可以支持多个主服务器写入。其它的都是从数据库的配置信息负责读取数据数量不限制。每次连接从服务器并且进行读取操作的时候系统会随机进行在从服务器中选择。CURD操作系统会自动判断当前执行的方法的读操作还是写操作如果你用的是原生SQL那么需要注意系统的默认规则写操作必须用模型的execute方法读操作必须用模型的query方法否则会发生主从读写错乱的情况。注意主从数据库的数据同步工作不在框架实现需要数据库考虑自身的同步或者复制机制。   9. 创建数据 在进行数据操作之前我们往往需要手动创建需要的数据例如对于提交的表单数据   // 获取表单的POST数据$data[name]  $_POST[name];$data[email]  $_POST[email]; // 更多的表单数据值获取 //……很简单的例子 // 实例化User模型$User  M(User); // 根据表单提交的POST数据创建数据对象$User-create(); // 把创建的数据对象写入数据库$User-add();Create方法支持从其它方式创建数据对象例如从其它的数据对象或者数组等 $data[name]  ThinkPHP;$data[email]  ThinkPHPgmail.com;$User-create($data);甚至还可以支持从对象创建新的数据对象 // 从User数据对象创建新的Member数据对象$User  M(User);$User-find(1);$Member  M(Member);$Member-create($User);Create方法创建的数据对象是保存在内存中并没有实际写入到数据库中直到使用add或者save方法才会真正写入数据库。 因此在没有调用add或者save方法之前我们都可以改变create方法创建的数据对象例如$User  M(User);$User-create(); //创建User数据对象$User-status  1; // 设置默认的用户状态$User-create_time  time(); // 设置用户的创建时间$User-add(); // 把用户对象写入数据库如果只是想简单创建一个数据对象并不需要完成一些额外的功能的话可以使用data方法简单的创建数据对象。使用如下// 实例化User模型$User  M(User); // 创建数据后写入到数据库$data[name]  ThinkPHP;$data[email]  ThinkPHPgmail.com;$User-data($data)-add();Data方法也支持传入数组和对象使用data方法创建的数据对象不会进行自动验证和过滤操作请自行处理。但在进行add或者save操作的时候数据表中不存在的字段以及非法的数据类型例如对象、数组等非标量数据是会自动过滤的不用担心非数据表字段的写入导致SQL错误的问题。 安全提示create方法如果没有传值默认取$_POST数据如果用户提交的变量内容含有可执行的html代码请进行手工过滤。$_POST[title]  scriptalert(1);/script;非法html代码可以使用htmlspecialchars进行编码以防止用户提交的html代码在展示时被执行以下是两种安全处理方法。$_POST[title]  htmlspecialchars($_POST[title]);M(User)-create();$data[title]  $this-_post(title, htmlspecialchars);M(User)-create($data); 10. 字段映射 ThinkPHP的字段映射功能可以让你在表单中隐藏真正的数据表字段而不用担心放弃自动创建表单对象的功能假设我们的User表里面有username和email字段我们需要映射成另外的字段定义方式如下Class UserModel extends Model{    protected $_map  array(        name username, // 把表单中name映射到数据表的username字段        mail  email, // 把表单中的mail映射到数据表的email字段    ); }这样在表单里面就可以直接使用name和mail名称作为表单数据提交了。在保存的时候会字段转换成定义的实际数据表字段。字段映射还可以支持对主键的映射。 如果我们需要把数据库中的数据显示在表单中并且也支持字段映射的话需要对查询的数据进行一下处理处理方式是调用Model类的parseFieldsMap方法例如// 实例化User模型$User  M(User);$data  $User-find(3);这个时候取出的data数据包含的是实际的username和email字段为了方便便表单输出我们需要处理成字段映射显示在表单中就需要使用下面的代码处理$data  $User-parseFieldsMap($data);这样一来data数据中就包含了name和mail字段数据了而不再有username和email字段数据了。  11. 连贯操作 ThinkPHP模型基础类提供的连贯操作方法可以有效的提高数据存取的代码清晰度和开发效率并且支持所有的CURD操作。使用也比较简单 假如我们现在要查询一个User表的满足状态为1的前10条记录并希望按照用户的创建时间排序 代码如下$User-where(status1)-order(create_time)-limit(10)-select();这里的where、order和limit方法就被称之为连贯操作方法T除了select方法必须放到最后一个外因为select方法并不是连贯操作方法连贯操作T的方法调用顺序没有先后例如下面的代码和上面的等效$User-order(create_time)-limit(10)-where(status1)-select();如果不习惯使用连贯操作的话还支持直接使用参数进行查询的方式。例如上面的代码可以改写为$User-select(array(ordercreate_time,wherestatus1,limit10));使用数组参数方式的话索引的名称就是连贯操作的方法名称。其实T不仅仅是查询方法可以使用连贯操作包括所有的CURD方法都可以使用例如$User-where(id1)-field(id,name,email)-find(); $User-where(status1 and id1)-delete();连贯操作通常只有一个参数并且仅在当此查询或者操作有效完成后会自动清空连贯操作的所有传值有个别特殊的连贯操作有多个参数并且会记录当前的传值。简而言之连贯操作的结果不会带入以后的查询。系统支持的连贯操作方法有 连贯操作作用支持的参数类型where用于查询或者更新条件的定义字符串、数组和对象table用于定义要操作的数据表名称字符串和数组alias用于给当前数据表定义别名字符串data用于新增或者更新数据之前的数据对象赋值数组和对象field用于定义要查询的字段支持字段排除字符串和数组order用于对结果排序字符串和数组limit用于限制查询结果数量字符串和数字page用于查询分页内部会转换成limit字符串和数字group用于对查询的group支持字符串having用于对查询的having支持字符串join*用于对查询的join支持字符串和数组union*用于对查询的union支持字符串、数组和对象distinct用于查询的distinct支持布尔值lock用于数据库的锁机制布尔值cache用于查询缓存支持多个参数relation用于关联查询需要关联模型支持字符串 所有的连贯操作都返回当前的模型实例对象this其中带*标识的表示支持多次调用。 可参考http://doc.thinkphp.cn/manual/continuous_operation.html 12. CURD操作 创建Create 在ThinkPHP中使用add方法新增数据到数据库而并不是create方法。 使用示例如下$User  M(User); // 实例化User对象$data[name]  ThinkPHP;$data[email]  ThinkPHPgmail.com;$User-add($data);或者使用data方法连贯操作$User-data($data)-add();如果在add之前已经创建数据对象的话例如使用了create或者data方法add方法就不需要再传入数据了。 使用create方法的例子$User  M(User); // 实例化User对象 // 根据表单提交的POST数据创建数据对象$User-create();$User-add(); // 根据条件保存修改的数据如果你的主键是自动增长类型并且如果插入数据成功的话Add方法的返回值就是最新插入的主键值可以直接获取。 读取Read 在ThinkPHP中读取数据的方式很多通常分为读取数据和读取数据集。 读取数据集使用select方法新版已经废除原来的findall方法 使用示例$User  M(User); // 实例化User对象 // 查找status值为1的用户数据 以创建时间排序 返回10条数据$list  $User-where(status1)-order(create_time)-limit(10)-select();Select方法配合连贯操作方法可以完成复杂的数据查询。而最复杂的连贯方法应该是where方法的使用。 读取数据使用find方法 读取数据的操作其实和数据集的类似select可用的所有连贯操作方法也都可以用于find方法区别在于find方法最多只会返回一条记录因此limit方法对于find查询操作是无效的。 $User  M(User); // 实例化User对象 // 查找status值为1name值为think的用户数据 $User-where(status1 AND namethink)-find();即使满足条件的数据不止一条find方法也只会返回第一条记录。 如果要读取某个字段的值可以使用getField方法 示例如下$User  M(User); // 实例化User对象 // 获取ID为3的用户的昵称 $nickname  $User-where(id3)-getField(nickname);当只有一个字段的时候默认返回一个值。如果需要返回数组可以用$this-getField(id,true); // 获取id数组如果传入多个字段的话默认返回一个关联数组$User  M(User); // 实例化User对象 // 获取所有用户的ID和昵称列表 $list  $User-getField(id,nickname);返回的list是一个数组键名是用户的id 键值是用户的昵称nickname。如果传入多个字段的名称例如$list  $User-getField(id,nickname,email);返回的是一个二维数组类似select方法的返回结果区别的是这个二维数组的键名是用户的id准确的说是getField方法的第一个字段名。如果我们传入一个字符串分隔符$list  $User-getField(id,nickname,email,:);那么返回的结果就是一个数组键名是用户id键值是 nickname:email的输出字符串。getField方法的sepa参数还可以支持限制数量例如$this-getField(id,name,5); // 限制返回5条记录$this-getField(id,3); // 获取id数组 限制3条记录可以配合使用order方法使用。 更新Update 在ThinkPHP中使用save方法更新数据库并且也支持连贯操作的使用。 $User  M(User); // 实例化User对象 // 要修改的数据对象属性赋值$data[name]  ThinkPHP;$data[email]  ThinkPHPgmail.com;$User-where(id5)-save($data); // 根据条件保存修改的数据为了保证数据库的安全避免出错更新整个数据表如果没有任何更新条件数据对象本身也不包含主键字段的话save方法不会更新任何数据库的记录。因此下面的代码不会更改数据库的任何记录$User-save($data); 除非使用下面的方式$User  M(User); // 实例化User对象 // 要修改的数据对象属性赋值$data[id]  5;$data[name]  ThinkPHP;$data[email]  ThinkPHPgmail.com;$User-save($data); // 根据条件保存修改的数据如果id是数据表的主键的话系统自动会把主键的值作为更新条件来更新其他字段的值。还有一种方法是通过create或者data方法创建要更新的数据对象然后进行保存操作这样save方法的参数可以不需要传入。$User  M(User); // 实例化User对象 // 要修改的数据对象属性赋值$data[name]  ThinkPHP;$data[email]  ThinkPHPgmail.com;$User-where(id5)-data($data)-save(); // 根据条件保存修改的数据使用create方法的例子$User  M(User); // 实例化User对象 // 根据表单提交的POST数据创建数据对象$User-create();$User-save(); // 根据条件保存修改的数据 如果只是更新个别字段的值可以使用setField方法。 使用示例$User  M(User); // 实例化User对象 // 更改用户的name值$User- where(id5)-setField(name,ThinkPHP);setField方法支持同时更新多个字段只需要传入数组即可例如$User  M(User); // 实例化User对象 // 更改用户的name和email的值$data  array(nameThinkPHP,emailThinkPHPgmail.com);$User- where(id5)-setField($data); 而对于统计字段通常指的是数字类型的更新系统还提供了setInc和setDec方法。 $User  M(User); // 实例化User对象$User-where(id5)-setInc(score,3); // 用户的积分加3$User-where(id5)-setInc(score); // 用户的积分加1$User-where(id5)-setDec(score,5); // 用户的积分减5$User-where(id5)-setDec(score); // 用户的积分减1 删除Delete 在ThinkPHP中使用delete方法删除数据库中的记录。 示例如下$User  M(User); // 实例化User对象$User-where(id5)-delete(); // 删除id为5的用户数据$User-where(status0)-delete(); // 删除所有状态为0的用户数据delete方法可以用于删除单个或者多个数据主要取决于删除条件也就是where方法的参数也可以用order和limit方法来限制要删除的个数例如// 删除所有状态为0的5 个用户数据 按照创建时间排序$User-where(status0)-order(create_time)-limit(5)-delete();  可参见http://doc.thinkphp.cn/manual/curd.html 13. ActiveRecord ThinkPHP实现了ActiveRecords模式的ORM模型采用了非标准的ORM模型表映射到类记录映射到对象。 下面我们用AR模式来换一种方式重新完成CURD操作。 一、创建数据$User  M(User); // 实例化User对象 // 然后直接给数据对象赋值$User-name  ThinkPHP;$User-email  ThinkPHPgmail.com; // 把数据对象添加到数据库$User-add();如果使用了create方法创建数据对象的话仍然可以在创建完成后进行赋值$User  D(User);$User-create(); // 创建User数据对象默认通过表单提交的数据进行创建 // 增加或者更改其中的属性$User-status  1;$User-create_time  time(); // 把数据对象添加到数据库$User-add();  二、查询记录 假如我们要查询主键为8的某个用户记录如果按照之前的方式 $User  M(User); // 实例化User对象 // 查找id为8的用户数据$User-where(id8)-find();用AR模式的话可以直接写成$User-find(8); 如果要根据某个字段查询例如查询姓名为ThinkPHP的可以用$User  M(User); // 实例化User对象$User-getByName(ThinkPHP); 如果要查询数据集可以直接使用 // 查找主键为1、3、8的多个数据$userList  $User-select(1,3,8);  三、更新记录在完成查询后可以直接修改数据对象然后保存到数据库。$User-find(1); // 查找主键为1的数据$User-name  TOPThink; // 修改数据对象$User-save(); // 保存当前数据对象上面这种方式仅仅是示例不代表保存操作之前一定要先查询。因为下面的方式其实是等效的$User-id  1;$User-name  TOPThink; // 修改数据对象$User-save(); // 保存当前数据对象 四、删除记录可以删除当前查询的数据对象$User-find(2);$User-delete(); // 删除当前的数据对象或者直接根据主键进行删除$User-delete(8); // 删除主键为8的数据$User-delete(5,6); // 删除主键为5、6的多个数据 14. 自动验证 大多数情况下面数据对象是由表单提交的$_POST数据创建。需要使用系统的自动验证功能只需要在Model类里面定义$_validate属性是由多个验证因子组成的二维数组。验证因子格式array(验证字段,验证规则,错误提示,[验证条件,附加规则,验证时间]) 示例protected $_validate  array(    array(verify,require,验证码必须), //默认情况下用正则进行验证    array(name,,帐号名称已经存在,0,unique,1), // 在新增的时候验证name字段是否唯一    array(value,array(1,2,3),值的范围不正确,2,in), // 当值不为空的时候判断是否在一个范围内    array(repassword,password,确认密码不正确,0,confirm), // 验证确认密码是否和密码一致    array(password,checkPwd,密码格式不正确,0,function), // 自定义函数验证密码格式 );当使用系统的create方法创建数据对象的时候会自动进行数据验证操作代码示例$User  D(User); // 实例化User对象 if (!$User-create()){    // 如果创建失败 表示验证没有通过 输出错误提示信息 exit($User-getError()); }else{    // 验证通过 可以进行其他数据操作 }通常来说每个数据表对应的验证规则是相对固定的但是有些特殊的情况下面可能会改变验证规则我们可以动态的改变验证规则来满足不同条件下面的验证$User  D(User); // 实例化User对象$validate  array(    array(verify,require,验证码必须), // 仅仅需要进行验证码的验证 );$User- setProperty(_validate,$validate);$result  $User-create(); if (!$result){    // 如果创建失败 表示验证没有通过 输出错误提示信息    exit($User-getError()); }else{    // 验证通过 可以进行其他数据操作 } 多字段验证自动验证功能中的function和callback规则可以支持多字段。例子protected $_validate  array(    array(user_id,good_id, checkIfOrderToday, 今天已经购买过请明天再来, 1,callback, 1), ); protected function checkIfOrderToday($data){    $map  $data;    $map[ctime]  array(array(gt,[开始时间]), array(lt, [结束时间]));    if($this-where($map)-find())        return false;    else        return true; }批量验证新版支持数据的批量验证功能只需要在模型类里面设置patchValidate属性为true 默认为false设置批处理验证后getError() 方法返回的错误信息是一个数组返回格式是array(字段名1错误提示1,字段名2错误提示2... )前端可以根据需要需要自行处理。 手动验证3.1版本开始可以使用validate方法实现动态和批量手动验证例如$this-validate($validate)-create();其中$validate变量的规范和_validate属性的定义规则一致而且还可以支持函数调用由于PHP本身的限制在类的属性定义中不能调用函数。通过这一改进以前需要支持数据自动验证必须定义模型类的情况已经不再出现你完全可以通过M方法实例化模型类后使用动态设置完成自动验证操作。另外还有一个check方法用于对单个数据的手动验证支持部分自动验证的规则用法如下 check(验证数据,验证规则,验证类型) 验证类型支持 in between equal length regex expire ip_allow ip_deny默认为regex 结果返回布尔值$model-check($value,email); $model-check($value,1,2,3,in); 可参见http://doc.thinkphp.cn/manual/auto_validate.html 15. 命名范围 首先定义_scope属性class NewsModel extends Model {    protected $_scope  array(        // 命名范围normal        normalarray(            wherearray(status1),        ),        // 命名范围latest        latestarray(            ordercreate_time DESC,            limit10,        ),    ); }_scope属性是一个数组每个数组项表示定义一个命名范围。 属性定义完成后接下来就是使用scope方法进行命名范围的调用了每调用一个命名范围就相当于执行了命名范围中定义的相关操作选项。 调用某个命名范围 最简单的调用方式就直接调用某个命名范围例如$Model-scope(normal)-select();$Model-scope(latest)-select();生成的SQL语句分别是SELECT * FROM think_news WHERE status1SELECT * FROM think_news ORDER BY create_time DESC LIMIT 10 调用多个命名范围 也可以支持同时调用多个命名范围定义例如$Model-scope(normal)-scope(latest)-select();或者简化为$Model-scope(normal,latest)-select();生成的SQL都是SELECT * FROM think_news WHERE status1 ORDER BY create_time DESC LIMIT 10如果两个命名范围的定义存在冲突则后面调用的命名范围定义会覆盖前面的相同属性的定义。 默认命名范围 系统支持默认命名范围功能如果你定义了一个default命名范围例如    protected $_scope  array(        // 默认的命名范围        defaultarray(            wherearray(status1),            limit10,        ),    );那么调用default命名范围可以直接使用$Model-scope()-select(); 命名范围调整 如果你需要在normal命名范围的基础上增加额外的调整可以使用$Model-scope(normal,array(limit5))-select();生成的SQL语句是SELECT * FROM think_news WHERE status1 LIMIT 5当然也可以在两个命名范围的基础上进行调整例如$Model-scope(normal,latest,array(limit5))-select();生成的SQL是SELECT * FROM think_news WHERE status1 ORDER BY create_time DESC LIMIT 5 自定义命名范围 又或者干脆不用任何现有的命名范围我直接传入一个命名范围$Model-scope(array(fieldid,title,limit5,wherestatus1,ordercreate_time DESC))-select();这样生成的SQL变成SELECT id,title FROM think_news WHERE status1 ORDER BY create_time DESC LIMIT 5与连贯操作混合使用 命名范围一样可以和之前的连贯操作混合使用例如定义了命名范围_scope属性protected $_scope  array(    normalarray(        wherearray(status1),        fieldid,title,        limit10,    ), );然后在使用的时候可以这样调用$Model-scope(normal)-limit(8)-order(id desc)-select();这样生成的SQL变成SELECT id,title FROM think_news WHERE status1 ORDER BY id desc LIMIT 8如果定义的命名范围和连贯操作的属性有冲突则后面调用的会覆盖前面的。如果是这样调用$Model-limit(8)-scope(normal)-order(id desc)-select();生成的SQL则是SELECT id,title FROM think_news WHERE status1 ORDER BY id desc LIMIT 10命名范围功能的优势在于可以一次定义多次调用并且在项目中也能起到分工配合的规范避免开发人员在写CURD操作的时候出现问题项目经理只需要合理的规划命名范围即可。 16. 自动完成 在Model类定义 $_auto 属性可以完成数据自动处理功能用来处理默认值、数据过滤以及其他系统写入字段。$_auto属性是由多个填充因子组成的数组。填充因子格式array(填充字段,填充内容,[填充条件,附加规则]) 示例protected $_auto  array (     array(status,1),  // 新增的时候把status字段设置为1    array(password,md5,1,function) , // 对password字段在新增的时候使md5函数处理    array(name,getName,1,callback), // 对name字段在新增的时候回调getName方法    array(create_time,time,2,function), // 对create_time字段在更新的时候写入当前时间戳 );使用自动填充可能会覆盖表单提交项目。其目的是为了防止表单非法提交字段。使用Model类的create方法创建数据对象的时候会自动进行表单数据处理。 和自动验证一样自动完成机制需要使用create方法才能生效。并且也可以在操作方法中动态的更改自动完成的规则。$auto  array (     array(password,md5,1,function) // 对password字段在新增的时候使md5函数处理 );$User- setProperty(_auto,$auto);$User-create(); 动态设置自动完成规则还可以使用auto方法动态设置自动完成规则例如$this-auto($auto)-create();其中$auto变量的规范和_auto属性的定义规则一致而且还可以支持函数调用由于PHP本身的限制在类的属性定义中不能调用函数。通过这一改进以前需要支持数据自动完成必须定义模型类的情况已经不再出现你完全可以通过M方法实例化模型类后使用动态设置完成自动完成操作。 17. 查询语言 查询方式 ThinkPHP可以支持直接使用字符串作为查询条件但是大多数情况推荐使用索引数组或者对象来作为查询条件因为会更加安全。一、使用字符串作为查询条件这是最传统的方式但是安全性不高例如 $User  M(User); // 实例化User对象$User-where(type1 AND status1)-select(); 最后生成的SQL语句是SELECT * FROM think_user WHERE type1 AND status1 二、使用数组作为查询条件$User  M(User); // 实例化User对象$condition[name]  thinkphp;$condition[status]  1; // 把查询条件传入查询方法$User-where($condition)-select(); 最后生成的SQL语句是SELECT * FROM think_user WHERE namethinkphp AND status1如果进行多字段查询那么字段之间的默认逻辑关系是 逻辑与 AND但是用下面的规则可以更改默认的逻辑判断通过使用 _logic 定义查询逻辑$User  M(User); // 实例化User对象$condition[name]  thinkphp;$condition[account]  thinkphp;$condition[_logic]  OR; // 把查询条件传入查询方法$User-where($condition)-select(); 最后生成的SQL语句是SELECT * FROM think_user WHERE namethinkphp OR accountthinkphp 三、使用对象方式来查询 这里以stdClass内置对象为例$User  M(User); // 实例化User对象 // 定义查询条件$condition  new stdClass(); $condition-name  thinkphp; $condition-status 1; $User-where($condition)-select(); 最后生成的SQL语句和上面一样SELECT * FROM think_user WHERE namethinkphp AND status1使用对象方式查询和使用数组查询的效果是相同的并且是可以互换的大多数情况下我们建议采用数组方式更加高效后面我们会以数组方式为例来讲解具体的查询语言用法。 表达式查询 上面的查询条件仅仅是一个简单的相等判断可以使用查询表达式支持更多的SQL查询语法并且可以用于数组或者对象方式的查询下面仅以数组方式为例说明查询表达式的使用格式$map[字段名] array(表达式,查询条件);表达式不分大小写支持的查询表达式有下面几种分别表示的含义是 表达式含义EQ等于NEQ不等于GT大于EGT大于等于LT小于ELT小于等于LIKE模糊查询[NOT] BETWEEN不在区间查询[NOT] IN不在IN 查询EXP表达式查询支持SQL语法快捷查询 新版增加了快捷查询方式可以进一步简化查询条件的写法例如一、实现不同字段相同的查询条件$User  M(User); // 实例化User对象$map[name|title]  thinkphp; // 把查询条件传入查询方法$User-where($map)-select(); 查询条件就变成 name thinkphp OR title thinkphp二、实现不同字段不同的查询条件$User  M(User); // 实例化User对象$map[statustitle] array(1,thinkphp,_multitrue); // 把查询条件传入查询方法$User-where($map)-select(); _multitrue必须加在数组的最后表示当前是多条件匹配这样查询条件就变成 status 1 AND title thinkphp 查询字段支持更多的例如$map[statusscoretitle] array(1,array(gt,0),thinkphp,_multitrue);查询条件就变成 status 1 AND score 0 AND title thinkphp注意快捷查询方式中“|”和“”不能同时使用。 区间查询 ThinkPHP支持对某个字段的区间查询例如$map[id]  array(array(gt,1),array(lt,10)) ;得到的查询条件是 (id 1) AND (id 10)$map[id]  array(array(gt,3),array(lt,10), or) ;得到的查询条件是 (id 3) OR (id 10)$map[id]   array(array(neq,6),array(gt,3),and); 得到的查询条件是(id ! 6) AND (id 3)最后一个可以是AND、 OR或者 XOR运算符如果不写默认是AND运算。 组合查询 组合查询的主体还是采用数组方式查询只是加入了一些特殊的查询支持包括字符串模式查询_string、复合查询_complex、请求字符串查询_query混合查询中的特殊查询每次查询只能定义一个由于采用数组的索引方式索引相同的特殊查询会被覆盖。 一、字符串模式查询采用_string 作为查询条件数组条件还可以和字符串条件混合使用例如$User  M(User); // 实例化User对象$map[id]  array(neq,1);$map[name]  ok;$map[_string]  status1 AND score10;$User-where($map)-select(); 最后得到的查询条件就成了( id ! 1 ) AND ( name ok ) AND ( status1 AND score10 ) 二、请求字符串查询方式请求字符串查询是一种类似于URL传参的方式可以支持简单的条件相等判断。$map[id]  array(gt,100);$map[_query]  status1score100_logicor;得到的查询条件是id100 AND (status 1 OR score 100) 三、复合查询$where[name]   array(like, %thinkphp%);$where[title]   array(like,%thinkphp%);$where[_logic]  or;$map[_complex]  $where;$map[id]   array(gt,1);查询条件是 ( id  1) AND ( ( name like %thinkphp%) OR ( title like %thinkphp%) ) 统计查询 方法说明Count统计数量参数是要统计的字段名可选Max获取最大值参数是要统计的字段名必须Min获取最小值参数是要统计的字段名必须Avg获取平均值参数是要统计的字段名必须Sum获取总分参数是要统计的字段名必须 用法示例$User  M(User); // 实例化User对象获取用户数$userCount  $User-count();或者根据字段统计$userCount  $User-count(id);获取用户的最大积分$maxScore  $User-max(score);获取积分大于0的用户的最小积分$minScore  $User-where(score0)-min(score);获取用户的平均积分$avgScore  $User-avg(score);统计用户的总成绩$sumScore  $User-sum(score);并且所有的统计查询均支持连贯操作的使用。 定位查询 ThinkPHP支持定位查询但是要求当前模型必须继承高级模型类才能使用可以使用getN方法直接返回查询结果中的某个位置的记录。例如  获取符合条件的第3条记录$User-where(score0)-order(score desc)-getN(2); 获取符合条件的最后第二条记录$User- where(score80)-order(score desc)-getN(-2); 获取第一条记录$User-where(score80)-order(score desc)-first(); 获取最后一条记录$User-where(score80)-order(score desc)-last(); SQL查询 1、query方法 query  执行SQL查询操作用法query($sql,$parsefalse)参数query必须要查询的SQL语句parse可选是否需要解析SQL返回值 如果数据非法或者查询错误则返回false 否则返回查询结果数据集同select方法 使用示例$Model  new Model() // 实例化一个model对象 没有对应任何数据表$Model-query(select * from think_user where status1);如果你当前采用了分布式数据库并且设置了读写分离的话query方法始终是在读服务器执行因此query方法对应的都是读操作而不管你的SQL语句是什么。 2、execute方法 execute用于更新和写入数据的sql操作用法execute($sql,$parsefalse)参数query必须要执行的SQL语句parse可选是否需要解析SQL返回值如果数据非法或者查询错误则返回false 否则返回影响的记录数 使用示例$Model  new Model() // 实例化一个model对象 没有对应任何数据表$Model-execute(update think_user set namethinkPHP where status1);如果你当前采用了分布式数据库并且设置了读写分离的话execute方法始终是在写服务器执行因此execute方法对应的都是写操作而不管你的SQL语句是什么。 3、其他技巧自动获取当前表名通常使用原生SQL需要手动加上当前要查询的表名如果你的表名以后会变化的话那么就需要修改每个原生SQL查询的sql语句了针对这个情况系统还提供了一个小的技巧来帮助解决这个问题。例如$model  M(User);$model-query(select * from __TABLE__ where status1);我们这里使用了__TABLE__ 这样一个字符串系统在解析的时候会自动替换成当前模型对应的表名这样就可以做到即使模型对应的表名有所变化仍然不用修改原生的sql语句。 支持连贯操作和SQL解析新版对query和execute两个原生SQL操作方法增加第二个参数支持 表示是否需要解析SQL 默认为false 表示直接执行sql 如果设为true 则会解析SQL中的特殊字符串 需要配合连贯操作。例如支持 如下写法$model-table(think_user)      -where(array(namethinkphp))      -field(id,name,email)      -query(select %FIELD% from %TABLE% %WHERE%,true);其中query方法中的%FIELD%、%TABLE%和%WHERE%字符串会自动替换为同名的连贯操作方法的解析结果SQL支持的替换字符串包括 替换字符串对应连贯操作方法%FIELD%field%TABLE%table%DISTINCT%distinct%WHERE%where%JOIN%join%GROUP%group%HAVING%having%ORDER%order%LIMIT%limit%UNION%union 动态查询 借助PHP5语言的特性ThinkPHP实现了动态查询包括下面几种 方法名说明举例getBy根据某个字段的值查询数据例如getByName,getByEmailgetFieldBy根据某个字段查询并返回某个字段的值例如getFieldByNametop获取前多少条记录需要高级模型支持例如top8top12 一、getBy动态查询该查询方式针对数据表的字段进行查询。例如User对象拥有id,name,email,address 等属性那么我们就可以使用下面的查询方法来直接根据某个属性来查询符合条件的记录。$user  $User-getByName(liu21st);$user  $User-getByEmail(liu21stgmail.com);$user  $User-getByAddress(中国深圳);暂时不支持多数据字段的动态查询方法请使用find方法和select方法进行查询。 二、getFieldBy动态查询针对某个字段查询并返回某个字段的值例如$user  $User-getFieldByName(liu21st,id);表示根据用户的name获取用户的id值。 三、top动态查询ThinkPHP还提供了另外一种动态查询方式就是获取符合条件的前N条记录和定位查询一样也要求当前模型类必须继承高级模型类后才能使用。例如我们需要获取当前用户中积分大于0积分最高的前5位用户 $User- where(score80)-order(score desc)-top5();要获取积分的前8位可以改成$User- where(score80)-order(score desc)-top8(); 子查询 新版新增了子查询支持有两种使用方式1、使用select方法当select方法的参数为false的时候表示不进行查询只是返回构建SQL例如// 首先构造子查询SQL $subQuery  $model-field(id,name)-table(tablename)-group(field)-where($where)-order(status)-select(false); 2、使用buildSql方法$subQuery  $model-field(id,name)-table(tablename)-group(field)-where($where)-order(status)-buildSql(); 调用buildSql方法后不会进行实际的查询操作而只是生成该次查询的SQL语句为了避免混淆会在SQL两边加上括号然后我们直接在后续的查询中直接调用。// 利用子查询进行查询 $model-table($subQuery. a)-where()-order()-select() 构造的子查询SQL可用于TP的连贯操作方法例如table where等。 18. 查询锁定 ThinkPHP支持查询或者更新的锁定只需要在查询或者更新之前使用lock方法即可。查询锁定使用$list  $User-lock(true)-where(status1)-order(create_time)-limit(10)-select();更新锁定使用$list  $User-lock(true)-where(status1)-data($data)-save(); 19. 字段排除 当使用下面的字段排除方式查询的时候$Model-field(create_time,read_count,comment_count,true); 第二个参数表示field方法采用的是排除机制因此实际查询的字段是除create_time,read_count,comment_count之外的其他数据表所有字段最终要查询的字段根据实际的数据表字段有所不同。生成的SQL语句就变成了SELECT id,name,title,status FROM article 20. 事务支持 ThinkPHP提供了单数据库的事务支持如果要在应用逻辑中使用事务。事务是针对数据库本身的所以可以跨模型操作的 。 例如//  在User模型中启动事务$User-startTrans(); // 进行相关的业务逻辑操作$Info  M(Info); // 实例化Info对象$Info-save($User); // 保存用户信息 if (操作成功){    // 提交事务    $User-commit();  }else{   // 事务回滚   $User-rollback();  }注意系统提供的事务操作方法必须有数据库本身的支持如果你的数据库或者数据表类型不支持事务那么系统的事务操作是无效的。 21. 高级模型 http://doc.thinkphp.cn/manual/adv_model.html 22. 视图模型 http://doc.thinkphp.cn/manual/view_model.html 23. 关联模型 http://doc.thinkphp.cn/manual/relation_model.html 24. Mongo模型 http://doc.thinkphp.cn/manual/mongo_model.html 25. 动态模型 你可以从基本模型切换到高级模型或者视图模型而当前的数据不会丢失并可以控制要传递的参数和动态赋值。 要切换模型可以使用$User  M(User); // 实例化User对象 是基础模型类的实例 // 动态切换到高级模型类 执行top10查询操作$User-switchModel(Adv)-top10();上面的写法也可以改成$User  M(AdvModel:User); // 实例化User对象 是基础模型类的实例$User-top10(); 如果要传递参数可以使用$User  D(User); // 实例化User对象 是基础模型类的实例 // 动态切换到视图模型类 并传入viewFields属性$UserView  $User-switchModel(View,array(viewFields));如果要动态赋值可以使用$User  M(User); // 实例化User对象 是基础模型类的实例 // 动态切换到关联模型类 并传入data属性$advUser  $User-switchModel(Relation); // 或者在切换模型后再动态赋值给新的模型$advUser-setProperty(_link,$link); // 查找关联数据$user  $advUser-relation(true)-find(1); 26. 虚拟模型 有些时候我们建立模型类但又不需要进行数据库操作仅仅是借助模型类来封装一些业务逻辑那么可以借助虚拟模型来完成。虚拟模型不会自动连接数据库因此也不会自动检测数据表和字段信息有两种方式可以定义虚拟模型第一种:继承Model类Class UserModel extends Model {    Protected $autoCheckFields  false; }设置autoCheckFields属性为false后就会关闭字段信息的自动检测因为ThinkPHP采用的是惰性数据库连接只要你不进行数据库查询操作是不会连接数据库的。 1 第二种:不继承Model类Class UserModel { }这种方式下面自定义模型类就是一个单纯的业务逻辑类不能再使用模型的CURD操作方法但是可以实例化其他的模型类进行相关操作也可以在需要的时候直接实例化Db类进行数据库操作。 3.1版本开始模型层M支持自定义分层。并且D方法增加layer参数具体分层的M类仍然继承Model类用法示例实例化UserModel类默认的情况文件位于项目的Lib/Model/UserModel.class.phpD(User);实例化UserLogic类 实现Logic分层文件位于项目的Lib/Logic/UserLogic.class.phpD(User,Logic);实例化UserService类实现Service分层文件位于项目的Lib/Service/UserService.class.phpD(User,Service);可以配置DEFAULT_M_LAYER修改默认的模型层名称该参数默认值为Model ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 视图 ThinkPHP的视图有两个部分组成View类和模板文件。Action控制器直接和View视图类打交道把要输出的数据通过模板变量赋值的方式传递到视图类而具体的输出工作则交由View视图类来进行同时视图类还和模板引擎进行接口包括完成布局渲染、输出替换、页面Trace等功能。 1. 模板定义 为了对模板文件更加有效的管理ThinkPHP对模板文件进行目录划分默认的模板文件定义规则是模板目录/[分组名/][模板主题/]模块名/操作名模板后缀模板目录默认是项目下面的Tpl 当定义分组的情况下会按照分组名分开子目录新版模板主题默认是空表示不启用模板主题功能模板主题功能是为了多模板切换而设计的如果有多个模板主题的话可以用DEFAULT_THEME参数设置默认的模板主题名。在每个模板主题下面是以项目的模块名为目录然后是每个模块的具体操作模板文件例如User模块的add操作 对应的模板文件就应该是Tpl/User/add.html 模板文件的默认后缀的情况是.html也可以通过TMPL_TEMPLATE_SUFFIX来配置成其他的。如果项目启用了模块分组功能假设User模块属于Home分组那么默认对应的模板文件可能变成 Tpl/Home/User/add.html 当然分组功能也提供了TMPL_FILE_DEPR参数来配置简化模板的目录层次。例如 TMPL_FILE_DEPR如果配置成“_”的话默认的模板文件就变成了Tpl/Home/User_add.html正是因为系统有这样一种模板文件自动识别的规则所以通常的display方法无需带任何参数即可输出对应的模板。 2. 模板赋值 要在模板中输出变量必须在在Action类中把变量传递给模板视图类提供了assign方法对模板变量赋值无论何种变量类型都统一使用assign赋值。$this-assign(name,$value); // 下面的写法是等效的$this-name  $value;系统只会输出设定的变量其它变量不会输出一定程度上保证了变量的安全性。 如果要同时输出多个模板变量可以使用下面的方式$array[name]        thinkphp;$array[email]        liu21stgmail.com;$array[phone]        12335678;$this-assign($array); 模板变量赋值后怎么在模板文件中输出需要根据选择的模板引擎来用不同的方法如果使用的是内置的模板引擎请参考后面的模板指南部分。如果你使用的是PHP本身作为模板引擎的话 就可以直接在模板文件里面输出了如下?php     echo $name.[.$email..$phone.]; 如果要获得全部的模板变量可以调用View类的get方法支持获取全部模板变量的值例如$this-get(name); // 获取name模板变量的值$this-get(); // 获取所有模板赋值变量的值 3. 模板输出 模板变量赋值后就需要调用模板文件来输出相关的变量模板调用通过display方法来实现。我们在操作方法的最后使用$this-display();就可以输出模板。 一、调用当前模块的其他操作模板 格式display(操作名)例如假设当前操作是User模块下面的read操作我们需要调用User模块的edit操作模版使用$this-display(edit); 不需要写模板文件的路径和后缀。 二、调用其他模块的操作模板 格式display(模块名:操作名)例如当前是User模块我们需要调用Member模块的read操作模版 使用$this-display(Member:read);  三、调用其他主题的操作模板 格式display(主题名:模块名:操作名)例如我们需要 调用Xp主题的User模块的edit操作模版使用$this-display(Xp:User:edit); 这种方式需要指定模块和操作名 四、直接全路径输出模板 格式display(模板文件名)例如我们直接输出当前的Public目录下面的menu.html模板文件使用 $this-display(./Public/menu.html);这种方式需要指定模板路径和后缀这里的Public目录是位于当前项目入口文件位置下面。如果是其他的后缀文件也支持直接输出例如$this-display(./Public/menu.tpl);只要./Public/menu.tpl是一个实际存在的模板文件。如果使用的是相对路径的话要注意当前位置是相对于项目的入口文件而不是模板目录。 五、直接解析内容 Action类的display方法如果传入第四个参数表示不读取模板文件而是直接解析内容。例如$this-assign(foo,ThinkPHP); $this-show(Hello, {$foo}!);会在页面输出 Hello,ThinkPHP! 直接输出的内容仍然支持模板布局功能。show方法也可以支持指定编码和输出格式例如$this-show($content, utf-8, text/xml);  事实上display方法还有其他的参数和用法。有时候某个模板页面我们需要输出指定的编码而不是默认的编码可以使用$this-display(Member:read, gbk); 或者输出的模板文件不是text/html格式的而是XML格式的可以用$this-display(Member:read, utf-8, text/xml); 如果你的网站输出编码不是默认的编码可以使用DEFAULT_CHARSET gbk 如果要输出XML格式的可以用TMPL_CONTENT_TYPE text/xml 4. 模板替换 在进行模板输出之前系统还会对渲染的模板结果进行一些模板的特殊字符串替换操作也就是实现了模板输出的替换和过滤。模板替换适用于所有的模板引擎包括原生的PHP模板。这个机制可以使得模板文件的定义更加方便默认的替换规则有../Public 会被替换成当前项目的公共模板目录 通常是 /项目目录/Tpl/当前主题/Public/ __TMPL__ 会替换成项目的模板目录 通常是 /项目目录/Tpl/当前主题/注为了部署安全考虑../Public和__TMPL__不再建议使用__PUBLIC__会被替换成当前网站的公共目录 通常是 /Public/__ROOT__ 会替换成当前网站的地址不含域名 __APP__ 会替换成当前项目的URL地址 不含域名__GROUP__会替换成当前分组的URL地址 不含域名__URL__ 会替换成当前模块的URL地址不含域名__ACTION__会替换成当前操作的URL地址 不含域名__SELF__ 会替换成当前的页面URL注意这些特殊的字符串是严格区别大小写的并且这些特殊字符串的替换规则是可以更改或者增加的我们只需要在项目配置文件中配置TMPL_PARSE_STRING就可以完成。如果有相同的数组索引就会更改系统的默认规则。例如TMPL_PARSE_STRING  array(     __PUBLIC__  /Common, // 更改默认的/Public 替换规则     __JS__  /Public/JS/, // 增加新的JS类库路径替换规则     __UPLOAD__  /Uploads, // 增加新的上传路径替换规则 )有了模板替换规则后页面上所有的__PUBLIC__ 字符串都会被替换那如果确实需要输出__PUBLIC__ 字符串到模板呢我们可以通过增加替换规则的方式例如TMPL_PARSE_STRING  array(     --PUBLIC--  __PUBLIC__, // 采用新规则输出/Public字符串 )这样增加替换规则后如果我们要输出__PUBLIC__ 字符串只需要在模板中添加--PUBLIC--其他替换字符串的输出方式类似。 5. 获取内容 有些时候我们不想直接输出模板内容而是希望对内容再进行一些处理后输出就可以使用fetch方法来获取解析后的模板内容在Action类里面使用$content  $this-fetch();fetch的参数用法和Display方法基本一致也可以使用$content  $this-fetch(Member:read); 区别就在于display方法直接输出模板文件渲染后的内容而fetch方法是返回模板文件渲染后的内容。如何对返回的结果content进行处理完全由开发人员自行决定了。这是模板替换的另外一种高级方式比较灵活而且不需要通过配置的方式。注意fetch方法仍然会执行上面的模板替换操作。 6. 模板引擎 系统支持原生的PHP模板而且本身内置了一个基于XML的高效的编译型模板引擎系统默认使用的模板引擎是内置模板引擎关于这个模板引擎的标签详细使用可以参考模板指南部分。内置的模板引擎也可以直接支持在模板文件中采用PHP原生代码和模板标签的混合使用如果需要完全使用PHP本身作为模板引擎可以配置TMPL_ENGINE_TYPE PHP可以达到最佳的效率。如果你使用了其他的模板引擎只需要设置TMPL_ENGINE_TYPE参数为相关的模板引擎名称即可。 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 模板引擎 ThinkPHP内置了一个基于XML的性能卓越的模板引擎 ThinkTemplate这是一个专门为ThinkPHP服务的内置模板引擎。ThinkTemplate是一个使用了XML标签库技术的编译型模板引擎支持两种类型的模板标签使用了动态编译和缓存技术而且支持自定义标签库。 每个模板文件在执行过程中都会生成一个编译后的缓存文件其实就是一个可以运行的PHP文件。模板缓存默认位于项目的Runtime/Cache目录下面以模板文件的md5编码作为缓存文件名保存的。如果在模板标签的使用过程中发现问题可以尝试通过查看模板缓存文件找到问题所在。内置的模板引擎支持普通标签和XML标签方式两种标签定义分别用于不同的目的 普通标签主要用于输出变量和做一些基本的操作XML标签主要完成一些逻辑判断、控制和循环输出并且可扩展1. 变量输出 如果我们在Action中赋值了一个name模板变量$name  ThinkPHP;$this-assign(name,$name);使用内置的模板引擎输出变量只需要在模版文件使用{$name}模板编译后的结果就是?php echo($name);?注意模板标签的{和$之间不能有任何的空格否则标签无效。 普通标签默认开始标记是 {结束标记是 }。也可以通过设置TMPL_L_DELIM和TMPL_R_DELIM进行更改。例如我们在项目配置文件中定义TMPL_L_DELIM{, TMPL_R_DELIM},那么上面的变量输出标签就应该改成{$name} 如果TMPL_VAR_IDENTIFY设置为array那么{$user.name}和{$user[name]}等效也就是输出数组变量。如果TMPL_VAR_IDENTIFY设置为obj那么{$user.name}和{$user:name}等效也就是输出对象的属性。如果TMPL_VAR_IDENTIFY留空的话系统会自动判断要输出的变量是数组还是对象这种方式会一定程度上影响效率而且只支持二维数组和两级对象属性。 如果TMPL_VAR_IDENTIFY留空的话系统会自动判断要输出的变量是数组还是对象这种方式会一定程度上影响效率而且只支持二维数组和两级对象属性。如果是多维数组或者多层对象属性的输出可以使用下面的定义方式{$user.sub.name}// 使用点语法输出或者使用{$user[sub][name]}// 输出三维数组的值 {$user:sub:name}// 输出对象的多级属性 2. 系统变量 除了常规变量的输出外模板引擎还支持系统变量和系统常量、以及系统特殊变量的输出。它们的输出不需要事先赋值给某个模板变量。系统变量的输出必须以$Think.打头并且仍然可以支持使用函数。常用的系统变量输出包括下面 用法含义例子$Think.server获取$_SERVER{$Think.server.php_self}$Think.get获取$_GET{$Think.get.id}$Think.post获取$_POST{$Think.post.name}$Think.request获取$_REQUEST{$Think.request.user_id}$Think.cookie获取$_COOKIE{$Think.cookie.username}$Think.session获取$_SESSION{$Think.session.user_id}$Think.config获取系统配置参数{$Think.config.app_status}$Think.lang获取系统语言变量{$Think.lang.user_type}$Think.const获取系统常量{$Think.const.app_name}或{$Think.APP_NAME}$Think.env获取环境变量{$Think.env.HOSTNAME}$Think.version获取框架版本号{$Think.version}$Think.now获取当前时间{$Think.now}$Think.template获取当前模板{$Think.template}$Think.ldelim获取模板左界定符{$Think.ldelim}$Think.rdelim获取模板右界定符{$Think.rdelim} 1、系统变量包括server、session、post、get、request、cookie 2、系统常量使用$Think.const 输出 3、特殊变量由ThinkPHP系统内部定义的常量 4、配置参数输出项目的配置参数值{$Think.config.db_charset}输出的值和C(db_charset) 的返回结果是一样的。也可以输出二维的配置参数例如{$Think.config.user.user_name} 5、语言变量输出项目的当前语言定义值{$Think.lang.page_error}输出的值和L(page_error)的返回结果是一样的。 3. 使用函数 用于模板标签的函数可以是PHP内置函数或者是用户自定义函数和smarty不同用于模板的函数不需要特别的定义。 模板变量的函数调用格式为{$varname|function1|function2arg1,arg2,### }说明 { 和 $ 符号之间不能有空格 后面参数的空格就没有问题###表示模板变量本身的参数位置 支持多个函数函数之间支持空格 支持函数屏蔽功能在配置文件中可以配置禁止使用的函数列表 支持变量解析缓存功能重复变量字串不多次解析。 {$webTitle|md5|strtoupper|substr0,3}编译后的PHP代码就是?php echo (substr(strtoupper(md5($webTitle)),0,3)); ?注意函数的定义和使用顺序的对应关系通常来说函数的第一个参数就是前面的变量或者前一个函数调用的返回结果如果你的变量并不是函数的第一个参数需要使用定位符号例如{$create_time|datey-m-d,###}编译后的PHP是?php echo (date(y-m-d,$create_time)); ? 函数的使用没有个数限制但是可以允许配置TMPL_DENY_FUNC_LIST定义禁用函数列表系统默认禁用了exit和echo函数以防止破坏模板输出我们也可以增加额外的定义例如TMPL_DENY_FUNC_LISTecho,exit,halt多个函数之间使用半角逗号分隔即可。 并且还提供了在模板文件中直接调用函数的快捷方法这种方式更加直接明了而且无需通过模板变量包括两种方式1、执行函数并输出返回值格式{:function(…)} 例如输出U函数的返回值{:U(User/insert)}编译后的PHP代码是?php echo U(User/insert);?2、执行函数但不输出格式{~function(…)} 例如调用say_hello函数{~say_hello(ThinkPHP)}编译后的PHP代码是?php say_hello(ThinkPHP);? 4. 默认值输出 如果输出的模板变量没有值但是我们需要在显示的时候赋予一个默认值的话可以使用default语法格式{$变量|default默认值}这里的default不是函数而是系统的一个语法规则例如{$user.nickname|default这家伙很懒什么也没留下}对系统变量的输出也可以支持默认值例如{$Think.post.name|default名称为空}默认值支持Html语法。 5. 使用运算符 内置模板引擎包含了运算符的支持包括对“”“ –” “*” “/”和“%”的支持。 在使用运算符的时候不再支持点语法和常规的函数用法例如 {$user.score10} 是错误的 {$user[score]10} 是正确的 {$user[score]*$user[level]} 正确的 {$user[score]|myFun*10} 错误的 {$user[score]myFun($user[level])} 正确的 6. 内置标签 系统内置标签库的所有标签无需引入标签库即可直接使用。XML标签有两种包括闭合标签和开放标签一个标签在定义的时候就已经决定了是否是闭合标签还是开放标签不可混合使用例如闭合标签include fileread /开放标签gt namename value5value/gt 内置支持的标签和属性列表如下 标签名作用包含属性include包含外部模板文件闭合fileimport导入资源文件闭合 包括js css load别名file,href,type,value,basepathvolist循环数组数据输出name,id,offset,length,key,modforeach数组或对象遍历输出name,item,keyforFor循环数据输出name,from,to,before,stepswitch分支判断输出namecase分支判断输出必须和switch配套使用value,breakdefault默认情况输出闭合 必须和switch配套使用无compare比较输出包括eq neq lt gt egt elt heq nheq等别名name,value,typerange范围判断输出包括in notin between notbetween别名name,value,typepresent判断是否赋值namenotpresent判断是否尚未赋值nameempty判断数据是否为空namenotempty判断数据是否不为空namedefined判断常量是否定义namenotdefined判断常量是否未定义namedefine常量定义闭合name,valueassign变量赋值闭合name,valueif条件判断输出conditionelseif条件判断输出闭合  必须和if标签配套使用conditionelse条件不成立输出闭合 可用于其他标签无php使用php代码无 7. 包含文件 可以使用Include标签来包含外部的模板文件使用方法如下 include标签包含外部模板文件闭合闭合标签属性file必须要包含的模板文件支持变量1、 使用完整文件名包含格式include file完整模板文件名 /include file./Tpl/default/Public/header.html / 2、包含当前模块的其他操作模板文件格式include file操作名 /include fileread /操作模板无需带后缀。 4、包含其他模板主题的模块操作模板格式include file主题名:模块名:操作名 /include fileblue:User:read / 5、 用变量控制要导入的模版格式include file$变量名 /include file$tplName /给$tplName赋不同的值就可以包含不同的模板文件变量的值的用法和上面的用法相同。 无论你使用什么方式包含外部模板Include标签支持在包含文件的同时传入参数注意由于模板解析的特点从入口模板开始解析如果外部模板有所更改模板引擎并不会重新编译模板除非在调试模式下或者缓存已经过期。如果部署模式下修改了包含的外部模板文件后需要把模块的缓存目录清空否则无法生效。 3.1版本开始include标签支持导入多个模板用逗号分割即可例如include filefile1,file2 / 8. 导入文件 import标签包含外部模板文件闭合闭合标签属性file必须要包含的模板文件支持变量import typejs fileJs.Util.Array /Type属性默认是js。还可以支持多个文件批量导入例如 import fileJs.Util.Array,Js.Util.Date / 导入外部CSS文件必须指定type属性的值例如import typecss fileCss.common /上面的方式默认的import的起始路径是网站的Public目录如果需要指定其他的目录可以使用basepath属性例如import fileJs.Util.Array  basepath./Common / load标签采用url方式引入资源文件闭合闭合标签属性href必须要引入的资源文件url地址支持变量load href/Book/Tpl/Home/Public/Js/Common.js / load href/Book/Tpl/Home/Public/Css/common.css / 系统还提供了两个标签别名js和css 用法和load一致例如js href/Public/Js/Common.js / css href/Book/Tpl/Home/Public/Css/common.css / 9. Volist标签 Volist标签主要用于在模板中循环输出数据集或者多维数组。 volist标签循环输出数据闭合非闭合标签属性 name必须要输出的数据模板变量 id必须循环变量 offset可选要输出数据的offset length可选输出数据的长度 key可选循环的key变量默认值为i mod可选对key值取模默认为2 empty可选如果数据为空显示的字符串 通常模型的select方法返回的结果是一个二维数组可以直接使用volist标签进行输出。在Action中首先对模版赋值$User  M(User);$list  $User-select();$this-assign(list,$list);在模版定义如下循环输出用户的编号和姓名volist namelist idvo{$vo.id}{$vo.name} /volist 输出循环变量volist namelist idvo keyk {$k}.{$vo.name} /volist如果没有指定key属性的话默认使用循环变量i例如volist namelist idvo  {$i}.{$vo.name} /volist如果要输出数组的索引可以直接使用key变量和循环变量不同的是这个key是由数据本身决定而不是循环控制的例如volist namelist idvo  {$key}.{$vo.name} /volist 从2.1版开始允许在模板中直接使用函数设定数据集而不需要在控制器中给模板变量赋值传入数据集变量如volist name:fun(arg) idvo{$vo.name}/volist 10. Foreach标签 foreach标签也是用于循环输出 foreach标签循环输出数据闭合非闭合标签属性name必须要输出的数据模板变量item必须循环单元变量key可选循环的key变量默认值为keyforeach namelist itemvo    {$vo.id}    {$vo.name} /foreachForeach标签相对比volist标签简洁没有volist标签那么多的功能。优势是可以对对象进行遍历输出而volist标签通常是用于输出数组。 11. For标签 For标签用于实现for循环格式为 for标签循环输出数据闭合非闭合标签属性start必须循环变量开始值end必须循环变量结束值name可选循环变量名默认值为istep可选步进值默认值为1comparison可选判断条件默认为ltfor start开始值 end结束值 comparison step步进值 name循环变量名  /for for start1 end100{$i} /for解析后的代码是for ($i1;$i100;$i1){    echo $i; } 12. Switch标签 switch name变量  case value值1 break0或1输出内容1/case case value值2输出内容2/case default /默认情况 /switch 其中name属性可以使用函数以及系统变量例如switch nameThink.get.userId|abs    case value1admin/case    default /default /switch 对于case的value属性可以支持多个条件的判断使用”|”进行分割例如switch nameThink.get.type    case valuegif|png|jpg图像格式/case    default /其他格式 /switch Case标签还有一个break属性表示是否需要break默认是会自动添加break如果不要break可以使用switch nameThink.get.userId|abs    case value1 break0admin/case    case value2admin/case    default /default /switch 也可以对case的value属性使用变量例如switch nameUser.userId    case value$adminIdadmin/case    case value$memberIdmember/case    default /default /switch使用变量方式的情况下不再支持多个条件的同时判断。 13. 比较标签 比较标签 name变量 value值内容/比较标签 系统支持的比较标签以及所表示的含义分别是 eq或者 equal等于neq 或者notequal不等于gt大于egt大于等于lt小于elt小于等于heq恒等于nheq不恒等于例如要求name变量的值等于value就输出可以使用eq namename valuevaluevalue/eq 当name变量的值不小于5就输出egt namename value5value/egt 比较标签中的变量可以支持对象的属性或者数组甚至可以是系统变量 当vo对象的属性或者数组或者自动判断等于5就输出eq namevo.name value5{$vo.name}/eq 而且还可以支持对变量使用函数 当vo对象的属性值的字符串长度等于5就输出eq namevo:name|strlen value5{$vo.name}/eq变量名可以支持系统变量的方式例如eq nameThink.get.name valuevalue相等else/不相等/eq 14. 三元运算 模板可以支持三元运算符例如{$status?正常:错误} {$info[status]?$info[msg]:$info[error]}注意三元运算符中暂时不支持点语法。 15. 范围判断标签 Range标签用于判断某个变量是否在某个范围之内 范围判断标签包括innotinbetween notbetween闭合非闭合标签属性name必须变量名value必须要比较的范围值支持变量可以使用in标签来判断模板变量是否在某个范围内例如in nameidvalue1,2,3输出内容1/in如果判断不再某个范围内可以使用notin nameidvalue1,2,3输出内容2/notin 可以把上面两个标签合并成为in nameidvalue1,2,3输出内容1else/输出内容2/in 可以使用between标签来判断变量是否在某个区间范围内可以使用between nameidvalue1,10输出内容1/between可以使用notbetween标签来判断变量不在某个范围内notbetween nameidvalue1,10输出内容1/notbetween当使用between标签的时候value只需要一个区间范围也就是只支持两个值后面的值无效。 所有的范围判断标签的value属性都可以使用变量例如in nameidvalue$var输出内容1/in变量的值可以是字符串或者数组都可以完成范围判断。也可以直接使用range标签替换in和notin的用法range nameidvalue1,2,3typein输出内容1/range其中type属性的值可以用in或者notin。 16. Present标签和Empty标签 可以使用present标签来判断模板变量是否已经赋值 present标签和notpresent标签闭合非闭合标签属性name必须变量名配合可以结合else标签一起使用present namenamename已经赋值/present 如果判断没有赋值可以使用notpresent namenamename还没有赋值/notpresent可以把上面两个标签合并成为present namenamename已经赋值else / name还没有赋值/present 可以使用empty标签判断模板变量是否为空 empty标签和notempty标签闭合非闭合标签属性name必须变量名配合可以结合else标签一起使用empty namenamename为空值/empty 如果判断没有赋值可以使用notempty namenamename不为空/notempty可以把上面两个标签合并成为empty namenamename为空else / name不为空/empty 17. Defined标签和Define标签 可以使用defined标签判断常量是否已经有定义 defined标签和notdefined标签闭合非闭合标签属性name必须变量名defined nameNAMENAME常量已经定义/defined如果判断没有被定义可以使用notdefined nameNAMENAME常量未定义/notdefined可以把上面两个标签合并成为defined nameNAMENAME常量已经定义else / NAME常量未定义/defined 可以使用define标签进行常量定义 defined标签和notdefined标签闭合闭合标签属性name必须常量名value必须常量值支持变量配合可以结合else标签一起使用 define nameMY_DEFINE_NAMEvalue3/在运行模板的时候 定义了一个MY_DEFINE_NAME的常量。 18. Assign标签 可以使用assign标签进行赋值 assign标签在模板中给变量赋值闭合闭合标签属性name必须模板变量名value必须变量值支持变量assign namevar value123 /在运行模板的时候 赋值了一个var的变量值是123。 19. IF标签 用法示例if condition($name eq 1) OR ($name gt 100)  value1 elseif condition$name eq 2/value2 else / value3 /if 除此之外我们可以在condition属性里面使用php代码例如if conditionstrtoupper($user[name]) neq THINKPHPThinkPHP else / other Framework /if condition属性可以支持点语法和对象语法例如自动判断user变量是数组还是对象if condition$user.name neq ThinkPHPThinkPHP else / other Framework /if或者知道user变量是对象if condition$user:name neq ThinkPHPThinkPHP else / other Framework /if由于if标签的condition属性里面基本上使用的是php语法尽可能使用判断标签和Switch标签会更加简洁原则上来说能够用switch和比较标签解决的尽量不用if标签完成。因为switch和比较标签可以使用变量调节器和系统变量。如果某些特殊的要求下面IF标签仍然无法满足要求的话可以使用原生php代码或者PHP标签来直接书写代码。 20. 标签嵌套 模板引擎支持标签的多层嵌套功能可以对标签库的标签指定可以嵌套。系统内置的标签中volist、switch、if、elseif、else、foreach、compare包括所有的比较标签、notpresent、notempty、notdefined等标签都可以嵌套使用。例如volist namelist idvo    volist namevo[sub] idsub        {$sub.name}    /volist /volist上面的标签可以用于输出双重循环。默认的嵌套层次是3级所以嵌套层次不能超过3层如果需要更多的层次可以指定TAG_NESTED_LEVEL配置参数例如TAG_NESTED_LEVEL 5可以改变循环嵌套级别为5级。 21. 使用PHP代码 phpecho Hello,world!;/php 注意php标签或者php代码里面就不能再使用标签包括普通标签和XML标签了因此下面的几种方式都是无效的phpeq namenamevaluevaluevalue/eq/php 简而言之在PHP标签里面不能再使用PHP本身不支持的代码。如果设置了TMPL_DENY_PHP参数为true就不能在模板中使用原生的PHP代码但是仍然支持PHP标签输出。 22. 模板布局 第一种方式是 以布局模板为入口的方式该方式需要配置开启LAYOUT_ON 参数默认不开启并且设置布局入口文件名LAYOUT_NAME默认为layout。开启LAYOUT_ON后我们的模板渲染流程就有所变化例如Class UserAction extends Action {    Public function add() {    $this-display(add);    } }在不开启LAYOUT_ON布局模板之前会直接渲染Tpl/User/add.html 模板文件,开启之后首先会渲染Tpl/layout.html 模板布局模板的写法和其他模板的写法类似本身也可以支持所有的模板标签以及包含文件区别在于有一个特定的输出替换变量{__CONTENT__}例如下面是一个典型的layout.html模板的写法{__CONTENT__}读取layout模板之后会再解析User/add.html 模板文件并把解析后的内容替换到layout布局模板文件的{__CONTENT__} 特定字符串。采用这种布局方式的情况下一旦User/add.html 模板文件或者layout.html布局模板文件发生修改都会导致模板重新编译。如果项目需要使用不同的布局模板可以动态的配置LAYOUT_NAME参数实现。如果某些页面不需要使用布局模板功能可以在模板文件开头加上 {__NOLAYOUT__} 字符串。如果上面的User/add.html 模板文件里面包含有{__NOLAYOUT__}则即使当前开启布局模板也不会进行布局模板解析。 第二种方式是以当前输出模板为入口的方式以前面的输出模板为例这种方式的入口还是在User/add.html 模板但是我们可以修改下add模板文件的内容在头部增加下面的布局标签layout namelayout /表示当前模板文件需要使用layout.html 布局模板文件而布局模板文件的写法和上面第一种方式是一样的。当渲染User/add.html 模板文件的时候如果读取到layout标签则会把当前模板的解析内容替换到layout布局模板的{__CONTENT__} 特定字符串。如果需要使用其他的布局模板可以改变layout的name属性例如layout namenew_layout /由于所有include标签引入的文件都支持layout标签所以我们可以借助layout标签和include标签相结合的方式实现布局模板的嵌套。例如上面的例子include filePublic:header / div idmain classmain {__CONTENT__} /div include filePublic:bottom / 在引入的header和footer模板文件中也可以添加layout标签例如header模板文件的开头添加如下标签layout namemenu /这样就实现了在头部模板中引用了menu布局模板。也可以采用两种布局方式的结合可以实现更加复杂的模板布局以及嵌套功能。 23. 模板继承 模板继承的优势其实是设计基础模板中的区块block和子模板中替换这些区块。每个区块由block/block标签组成并且不支持block标签的嵌套。 下面就是基础模板中的一个典型的区块设计用于设计网站标题block nametitletitle网站标题/title/block block标签必须指定name属性来标识当前区块的名称这个标识在当前模板中应该是唯一的block标签中可以包含任何模板内容包括其他标签和变量例如block nametitletitle{$web_title}/title/block你甚至还可以在区块中加载外部文件block nameincludeinclude filePublic:header //block 在子模板中可以对基础模板中的区块进行重载定义如果没有重新定义的话则表示沿用基础模板中的区块定义如果定义了一个空的区块则表示删除基础模板中的该区块内容。 24. 原样输出 literal标签保持原样输出闭合非闭合标签属性无 可以使用literal标签来防止模板标签被解析例如literal    if condition$name eq 1  value1    elseif condition$name eq 2/value2        else / value3    /if /literal上面的if标签被literal标签包含因此if标签里面的内容并不会被模板引擎解析而是保持原样输出。 Literal标签还可以用于页面的JS代码外层确保JS代码中的某些用法和模板引擎不产生混淆。总之所有可能和内置模板引擎的解析规则冲突的地方都可以使用literal标签处理。 25. 模板注释 模板支持注释功能该注释文字在最终页面不会显示仅供模板制作人员参考和识别。 {// 这是模板注释内容 } {/* 这是模板注释内容*/ }模板注释支持多行模板注释在生成编译缓存文件后会自动删除这一点和Html的注释不同。 26. 引入标签库 格式tagLib name标签库1[,标签库2,…]/可以同时导入多个标签库用逗号分隔例如tagLib namehtml/表示在当前模板文件需要引入html标签库。要引入标签库必须确保有Html标签库的定义文件和解析类库如何扩展这种方式请参考前面的标签库扩展部分。 引入后html标签库的所有标签在当前模板页面中都可以使用了。外部导入的标签库必须使用标签库前缀的xml标签避免两个不同的标签库中存在同名的标签定义例如假设Html标签库中已经有定义select和link标签html:select optionsname selectedvalue / html:link href/path/to/common.js /标签库使用的时候忽略大小写因此下面的方式一样有效HTML:LINK HREF/path/to/common.js /如果你的每个模板页面都需要加载Html标签库的话也可以通过配置直接预先加载Html标签库。 TAGLIB_PRE_LOAD  html ,如果有多个标签库需要预先加载的话用逗号分隔。定义之后每个模板页面都可以直接使用html:select optionsname selectedvalue /而不需手动引入Html标签库。假设你确信Html标签库无论在现在还是将来都不会和系统内置的标签库存在相同的标签那么可以配置TAGLIB_BUILD_IN的值把Html标签库作为内置标签库引入例如TAGLIB_BUILD_IN  cx,html ,这样也无需在模板文件页面引入Html标签库了并且可以不带前缀直接使用Html标签库的标签select optionsname selectedvalue /注意cx标签库是系统内置标签库不能删除定义。 27. 修改定界符 要更改普遍模板的起始标签和结束标签请使用下面的配置参数TMPL_L_DELIM  //模板引擎普通标签开始标记 TMPL_R_DELIM    //模板引擎普通标签结束标记例如在项目配置文件中增加下面的配置TMPL_L_DELIM, 普通模板标签主要用于模板变量输出和模板注释。如果要使用其它功能请使用XML模板标签。XML模板标签可以用于模板变量输出、文件包含、条件控制、循环输出等功能而且完全可以自己扩展功能。如果你觉得XML标签无法在正在使用的编辑器里面无法编辑还可以更改XML标签库的起始和结束标签请修改下面的配置参数TAGLIB_BEGIN    //标签库标签开始标签 TAGLIB_END    //标签库标签结束标记例如在项目配置文件中增加下面的配置TAGLIB_BEGIN[, TAGLIB_END], 注意XML标签和普通标签的定界符不能冲突否则会导致解析错误。如果你定制了普通表情的定界符而且默认跳转页面用的是系统默认的话记得修改下默认跳转模板中的变量定界符。 28. 避免JS混淆 如果使用内置的模板引擎而且采用默认的标签设置的话在某些情况下如果不注意{$(name).value} 这样的JS代码很容易被内置模板引擎误解析。有三个方法可以解决类似的混淆问题1、{$(name).value}改成{ $(name).value}因为内置模板引擎的解析规则是{后面紧跟$符号才会解析变量 因此只要在{ 和$之间添加空格就不会被误解析了2、使用内置的literal标签包含JS代码literalJS代码/literal 包含在literal标签中的代码将会直接输出不进行任何解析3、定制模板引擎标签的定界符例如TMPL_L_DELIM{,TMPL_R_DELIM}这样就和JS代码区别开来了。 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 日志 日志的处理工作是由系统自动进行的在开启日志记录的情况下会记录下允许的日志级别的所有日志信息。其中为了性能考虑SQL日志级别必须在调试模式开启下有效否则就不会记录。系统的日志记录由核心的Log类完成提供了多种方式记录了不同的级别的日志信息。 1. 日志级别 EMERG严重错误导致系统崩溃无法使用ALERT警戒性错误 必须被立即修改的错误CRIT临界值错误 超过临界值的错误ERR一般性错误WARN警告性错误 需要发出警告的错误NOTICE通知程序可以运行但是还不够完美的错误INFO信息程序输出信息DEBUG调试用于调试信息SQLSQL语句该级别只在调试模式开启时有效要开启日志记录必须在配置中开启LOG_RECORD参数以及可以在项目配置文件中配置需要记录的日志级别例如LOG_RECORD  true, // 开启日志记录 LOG_LEVEL  EMERG,ALERT,CRIT,ERR, // 只记录EMERG ALERT CRIT ERR 错误 2. 记录方式 记录方式说明常量标识SYSTEM日志发送到PHP的系统日志记录0MAIL日志通过邮件方式发送1FILE日志通过文件方式记录默认方式3SAPI日志通过SAPI方式记录4日志的记录格式记录时间 访问URL | 日志级别日志信息其中的时间显示可以动态配置默认是采用 [ c ]例如我们可以改成Log::$format  [ Y-m-d H:i:s ];其格式定义和date函数的用法一致默认情况下具体的日志信息类似于下面的内容[2012-01-15T18:09:2208:00] /Index/index|NOTIC: [8] Undefined variable: verify PublicAction.class.php 第 162 行. [2012-01-15T18:09:2208:00] /Index/index | SQL:  RunTime:0.214238s SQL  SHOW COLUMNS FROM think_user [2012-01-15T18:09:2208:00] /Index/index | SQL:  RunTime:0.039159s SQL  SELECT * FROM think_user WHERE ( account  admin ) AND ( status  0 ) LIMIT 1默认采用文件方式记录日志信息日志文件的命名格式是年简写_月_日.log例如09_10_01.log 表示2009年10月1日的日志文件可以设置LOG_FILE_SIZE参数来限制日志文件的大小超过大小的日志会形成备份文件。备份文件的格式是在当前文件名前面加上备份的时间戳例如1189571417-07_09_12.log 备份的日志文件 如果需要使用其他方式记录日志可以设置LOG_TYPE参数例如下面设置了采用邮件方式发送日志记录LOG_TYPE 1, //  采用邮件方式记录日志 LOG_DEST admindomain.com, // 要发送日志的邮箱 LOG_EXTRA From: webmasterexample.com, // 邮件的发件人设置 3. 手动记录 http://doc.thinkphp.cn/manual/log_record.html ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 错误 1. 异常处理 和PHP默认的异常处理不同ThinkPHP抛出的不是单纯的错误信息而是一个人性化的错误页面。 只有在调试模式下面才能显示具体的错误信息如果在部署模式下面你可能看到的是一个统一错误的提示文字如果你试图在部署模式下访问一个不存在的模块或者操作会发送404错误。调试模式下面一旦系统发生严重错误会自动抛出异常也可以用ThinkPHP定义的throw_exception方法手动抛出异常。 throw_exception(新增失败);throw_exception(信息录入错误,InfoException);同样也可以使用throw 关键字来抛出异常下面的写法是等效的throw new ThinkException(新增失败); throw new InfoException(信息录入错误);如果需要我们建议在项目的类库目录下面增加Exception目录用于专门存放异常类库以更加精确地定位异常。 2. 异常模板 系统内置的异常模板在系统目录的Tpl/think_exception.tpl可以通过修改系统模板来修改异常页面的显示。也通过设置TMPL_EXCEPTION_FILE 配置参数来修改系统默认的异常模板文件 例如TMPL_EXCEPTION_FILE  APP_PATH./Public/exception.tpl异常模板中可以使用的异常变量有$e[file]异常文件名$e[line] 异常发生的文件行数$e[message] 异常信息$e[trace] 异常的详细Trace信息因为异常模板使用的是原生PHP代码所以还可以支持任何的PHP方法和系统变量使用。 3. 异常显示 抛出异常后通常会显示具体的错误信息如果不想让用户看到具体的错误信息可以设置关闭错误信息的显示并设置统一的错误提示信息例如SHOW_ERROR_MSG false, ERROR_MESSAGE 发生错误设置之后所有的异常页面只会显示“发生错误”这样的提示信息但是日志文件中仍然可以查看具体的错误信息。新版如果关闭调试模式的话为了安全起见默认就是关闭异常信息提示。另外一种方式是配置ERROR_PAGE参数把所有异常和错误都指向一个统一页面从而避免让用户看到异常信息通常在部署模式下面使用。ERROR_PAGE参数必须是一个完整的URL地址例如ERROR_PAGE /Public/error.html如果不在当前域名还可以指定域名ERROR_PAGE http://www.myDomain.com/Public/error.html注意ERROR_PAGE所指向的页面不能再使用异常的模板变量了。 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------   转载于:https://www.cnblogs.com/echohao/p/4715421.html
http://www.yutouwan.com/news/113962/

相关文章:

  • 搬家网站怎么做网页设计素材模版
  • 南宁做棋牌网站的公司单页网站如何做cpa
  • 黄山建设网站公司网络运维工程师考试
  • 网站seo新手线上推广招聘
  • 河北网站优化网站广告图片设计教程
  • 免费制作网站net域名wordpress关注公众号可见
  • 美工设计网站推荐仿造网站用侵权吗
  • 机械模板网站wordpress怎么安装模板
  • 微商城微网站开发域名永久买入要多少钱
  • 网站访问量怎么做app定制
  • 西安专业网站建设公司排名做外贸网站一定要会英语吗
  • 佛山行业网站设计推广方式方法
  • 企业网站建设进度国内空间没备案可以打开网站吗
  • 网站建设经验总结成都网站设计网站
  • 安徽省教育基本建设学会网站浙江省建设厅官网
  • 电脑网站转换手机网站怎么做无锡企业网站公司
  • 景观毕业设计作品网站哈尔滨网站建设制作哪家好
  • 网站建设流程简图石家庄建设局网站怎么打不开
  • 重庆市城乡建设施工安全管理总站网站做移动网站优化排名
  • 网站页面设计说明怎么写博客html模板
  • 网站制作架构建设部网站证件查询
  • 徐州住房与城乡建设部网站wordpress显示作者的信息
  • 国外的有趣设计网站免费网页制作网站
  • 专业网站是指什么wordpress主题付费吗
  • 奈曼旗华水建设工程公司网站南宁360网
  • 网站建设模板研究广州网站建设电话咨询
  • 网站正在建设中 免费设计官网首页
  • 营销网站建设方案中国seo第一人
  • 网站建设初期的宣传深圳制作网站主页
  • 网站开发教学网站百度分享 wordpress