学习ThinkPHP5.1相关知识及php相关知识笔记

学习ThinkPHP5.1相关知识及php相关知识笔记
一、ThinkPHP5.1相关知识摘录
ThinkPHP是一个快速、简单的基于MVC和面向对象的轻量级PHP开发框架,使用ThinkPHP开发php网站有很多优点,如字写代码更简单方便快速,很多轮子不用重新造(如分页);代码阅读更直观(分离了html和php);安全问题thinkphp已做过考虑; 框架可以节省我们50-60%的工作量,我们全部精力都集中在业务层次;框架可以帮组我们快速、稳定、高效搭建程序系统...
目前(2020.03)版本选择:5.1.39。6.0版本目前较新,还不完善,用的人较少故暂时不用;

1、MVC模式
Model(模型)模型对象负责在数据库中存取数据。模型一般为对象,负责数据操作。通常是一个数据表对应一个模型对象。创建模型后模型自动关联同名的数据表。
View(视图)是应用程序中处理数据显示的部分,负责显示视图。通常表现为前端html。
Controller(控制器)是应用程序中处理用户交互的部分。 通常控制器负责从视图读取数据,控制用户输入,实现业务逻辑,如增删改查。
我们把 application 下面的子文件夹,称为模块(Module) ,把模块下的controller文件夹中的子文件称之为控制器(Controller) ,把控制器文件中的函数称为操作方法(Action) 。

2、ThinkPHP5中model与Db的区别:
tp5开始引入db类的,简单的说,如果直接增删改查可以用db就行了(db通常返回的是数组),而model返回的是对象,这就表明你可以在对象里加入一些处理数据的方法,属性。
使用DB方式是直接获取到的query类(ThinkPHP5/library/think/db/Query.php)的对象进行数据库的操作提供了基本的数据库curd操作功能。
使用model的方式是通过获取到模型对象然后在调用query类下的方法进行数据操作,但是在TP中的模型基类中还提供了较多的其他的方法可以方便使用例如获取器、修改器、数据完成等等功能。因此模型的功能更为强大。
就数据格式而言,在DB中是采用的“数组格式”使用。而在模型中统一使用“对象”。其中数据库交互后涉及到格式转换。因此在同等情况下db的数据略快与模型方式。
直接读取数据虽然简单易懂,但往往在大型的项目中却并不适用。如果实现一个功能,我们把所有的代码都写在 一个方法中,显然当功能复杂时,代码就会越来越长,越来越难以维护。这显然不是我们想看到的。 基于此,我们有了数据库M层,一个专门为我们处理数据表的文件。
因此对于ThinkPHP5使用DB与model的方式具体在编程中选择哪一个按照个人的观点并无强制要求。有时候为了项目中的封装采用模型方式可能更为合适一些。
下面是官方推荐的Db类用法(也就是每次都是静态方法调用)
// 查询单个数据
Db::name('user')->where('id', 1)->find();
// 查询多个数据
Db::name('user')->where('id', '>', 1)->select();
// 写入新的数据
Db::name('user')->insert(['name' => '张三']);
// 更新数据
Db::name('user')->where('id', 1)->update(['name' => '李四']);
// 删除数据
Db::name('user')->delete(1);
(5.1版本每次查询后是不会清空前次(5.0则会每次清空)的查询条件的,所以下面的用法是有效的。最佳实践:每次使用全新的Db静态查询)
模型的设计其实和Db一样,基本上不需要手动进行实例化。模型的实例化工作是由系统在查询或者写入数据的时候自动完成的。
// 写入新的数据
$user = User::create(['name' => '张三']);
// 更新数据
$user->update(['name' => '李四']);
// 查询单个数据
$user = User::get(1);
// 删除当前模型数据
$user->delete();
所以,模型请不要手动实例化模型,也不建议使用model助手函数。最佳实践:模型查询和创建都使用静态方法

3、目录结构
application 应用目录
config 应用配置目录
route 路由定义目录
public WEB目录(对外访问目录)
thinkphp 框架系统目录
extend 扩展类库目录
runtime 应用的运行时目录(可写,可定制)
vendor 第三方类库目录(Composer依赖库)
其它目录结构请查看手册(https://www.kancloud.cn/manual/thinkphp5_1/353950)

3、网址的访问
ThinkPHP5.1在没有定义路由的情况下典型的URL访问规则是:http://serverName/index.php/模块/控制器/操作方法/[参数名/参数值...]
在thinkphp中,是通过“入口文件/模块名(module)/控制器名(controller)/操作方法名(action)”(模块/控制器/操作方法)来确定用户的 URL对应执行哪个方法中的语句的。我们把application下面的子文件夹,称为模块(Module) ,把模块下的controller文件夹中的子文件称之为控制器(Controller) ,把控制器文件中的函数称为操作方法(Action) 。
(1)当我们未指定模块名时,调用的是默认模块index。
(2)当我们未指定控制器名时,调用的是默认控制器Index(注意,这个是Index,而不是index,原因是控制器实际上是一个类,我们规定类的名字首写字母要大写)。
(3)当我们在URL中未指定触发器名时,调用的是默认触发器index。
以上默认值可在config文件夹中的app.php中修改。
例如:
http://127.0.0.1/thinkphp5/public
http://127.0.0.1/thinkphp5/public/index.php
http://127.0.0.1/thinkphp5/public/index.php/index
http://127.0.0.1/thinkphp5/public/index.php/index/Index http://127.0.0.1/thinkphp5/public/index.php/index/Index/index 上述五种不同的URL之所以访问结果全部相同,是由于他们本身就是相同的。 原因是:默认值!
ThinkPHP 是个单入口框架,所有的入口都会进入 index.php 文件,通过 index.php来接收所有的http请求,请求中的所有参数都可以通过 Request 这个对象进行接收和处理。 在整个应用的生命周期中,第一步执行的就是入口文件,用户发起的请求都会经过应用的入口文件,通常是 public/index.php文件。首先服务器会进入入口文件index.php,再进入模块(如index文件夹),找到控制器(如index\controller\index.php),再调用里面的方法(如public function index())。配置文件app.php内已经默认设置了这些参数为index。
如果隐藏了入口文件index.php和设置了路由,则网址可以简短化。

4、隐藏index.php :
(可参考手册中的“架构”中的“URL设计”:https://www.kancloud.cn/manual/thinkphp5_1/353955)
以 Apache 为例,需要在入口文件的同级添加 .htaccess 文件(官方默认自带了该文件):
<IfModule mod_rewrite.c>
Options +FollowSymlinks -Multiviews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]//都是差别在这一句
</IfModule>
如果用的 phpstudy ,规则如下:
<IfModule mod_rewrite.c>
Options +FollowSymlinks -Multiviews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [L,E=PATH_INFO:$1]
</IfModule>
如果你使用的 apache 版本使用上面的方式无法正常隐藏 index.php ,可以尝试使用下面的方式配置 .htaccess 文件:
<IfModule mod_rewrite.c>
Options +FollowSymlinks -Multiviews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?/$1 [QSA,PT,L]
</IfModule>
如果是 Nginx 环境的话,可以在 Nginx.conf 中添加:
(找到nginx的配置文件 nginx.conf, 在里面的 server{ } 里增加以下内容)
location / {//…..省略部分代码
if (!-e $request_filename){
rewrite ^(.*)$ /index.php?s=/$1 last;
break;} }
thinkphp5 IIS7.5 隐藏index.php的方法:
web.config文件里:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="WPurls" enabled="true" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="index.php/{R:0}" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
根据不同的空间,请将上面的伪静态规则,保存为.htaccesss文件或Httpd.ini或web.config文件,并放到ThinkPHP项目入口文件同级目录下。
附:伪静态配置
Apache Rewrite的配置:Apache下的Rewrite配置主要有两种,一种是针对整个apache服务器的配置,此种配置的Rewrite规则是直接在httpd.conf下书写。另一种是针对apache服务器下的某一目录的配置,此种配置的Rewrite规则需在此目录下建立一个.htaccess文件来书写。
IIS 服务器:web.config 主要应用在iis7/iis7.5的服务器上,httpd.ini 主要应用在iis以及iis6 的服务器上,跟.htaccess的规则比较接近。
NGINX服务器:nginx里使用伪静态是直接在配置文件nginx.conf 中写规则的,在里面的 server{ } 中写需要的规则即可。

5、定义路由 :
默认的URL地址显得有点长,下面就来说说如何通过路由简化 URL访问。(感觉有点像字符串代替)
route目录下的任何路由定义文件都是有效的,默认的路由定义文件是route.php
我们在路由定义文件( route/route.php )里面添加一些路由规则,
Route::rule('路由表达式','路由地址','请求类型');//路由地址可为:模块/控制器/操作方法
例如:(前提是网址已经隐藏了入口文件index.php)
Route::rule('/', 'index/index/index');//index模块的index控制器的index操作方法
Route::rule('article/:id', 'index/index/article');//index模块的index控制器的article操作方法
定义后,我们访问:http://127.0.0.1 会自动路由到(相当于访问到):http://127.0.0.1/index/index/index (index方法中一般会有此句:return $this->fetch();关联到同名(fetch后没有指明则默认为文件名相同)的模板视图html文件);
我们访问:http://127.0.0.1/article/5 会自动路由到:http://127.0.0.1/index/index/article/id/5 ;
注意:定义路由规则后,原来的URL地址将会失效,变成非法请求。
【$this->fetch()表示:当前模块/view/当前控制器名(小写)/当前操作方法名(小写).html】
【application文件夹中的子文件夹称为模块(如application\admin),模块文件夹下的controller文件夹中的子文件*.php称为控制器(如application\admin\controller\Article.php),控制器文件中的函数称为操作方法(如Article.php中的public function add()叫做add方法)】

6、生成URL地址 :
ThinkPHP支持路由URL地址的统一生成,并且支持所有的路由方式,以及完美解决了路由地址的反转解析,无需再为路由定义和变化而改变URL生成。
URL生成使用 \think\facade\Url::build() 方法或者使用系统提供的助手函数url(),参数一致:
Url::build('地址表达式',['参数'],['URL后缀'],['域名'])
url('地址表达式',['参数'],['URL后缀'],['域名'])
例如:
url('index/blog/read', 'id=5&name=thinkphp');
以上方法都会生成下面的URL地址:/index.php/blog/5/name/thinkphp.html
我们能够定义路由,并实际的访问了 我们看一下 在网页上怎么运用,你可能会说,既然我们定义了路由。那么直接上链接上拼接上链接不就可以了,我想说 这样是万万不好的。比如说我的上面的链接 /hello/:id 在链接上直接输入,这样的。当前这可以访问。但是这样的链接在运营的过程中使用的越来越多 如果哪天看着这个链接不顺眼了。或者说,老板找你,把这个链接改一下。难道你要一个一个的去找去改吗,这样的很麻烦。既然说到这里了。必然会有解决办法的,我们可以看官方文档。url生成,我们在网页链接上直接按照原来“没有定义路由时”的思路来写链接,tp5 生成链接的方式是使用url类。如<a target="_blank" href="{:url('index/index/article',['id'=>$vo['id']])}">{$vo.title}</a>。而路由是Route::rule('info/:id', 'index/Info/index', 'GET');
这时打开网页 我们把鼠标放到标题上可以看到浏览器下方的状态栏上实际的链接就是我们需要的:域名/article/5.html

7、thinkphp5项目如何在虚拟主机部署:
第一步:移动入口文件位置,把它移动到根目录下,并修改index.php入口文件内容(可参考虑手册中的“架构”中的“入口文件”:tp5更改应用目录和入口位置,摘录如下)
tp5更改应用目录和入口位置:
新版框架默认不再支持改变应用目录(application)和入口文件位置,如果你需要更改,需要自己重新定义入口文件。
下面是一个例子(把入口文件放到应用根目录,并且更改应用目录名称为app):
<?php
namespace think;
// 定义应用目录
define('APP_PATH', __DIR__ . '/app/');
// 加载框架基础引导文件
require __DIR__ . '/thinkphp/base.php';
// 添加额外的代码
// ...
// 执行应用并响应用
Container::get('app')->path(APP_PATH)->run()->send();
另,更改应用目录名称和位置可能导致默认的命令行操作失效,你需要同步自定义根目录下面的think文件。
第二步:把.htaccess文件也移动到根目录下(IIS服务器则是web.config文件),可参考上面的隐藏index.php内容
第三步:把public目录中的static文件夹移到网站根目录(或者全部视图文件中所有用到路径的地方全部替换目录,/public/static。特别容易忽略的地方是css里面的background路径,和自定义上传路径)
控制器的php文件中上传路径处理方法:可在application文件夹中的common.php文件定义常量: define('WEB_static', \think\facade\Env::get('ROOT_PATH') .DIRECTORY_SEPARATOR .'static');,然后在控制器的php文件中就可以引用这个常量:如$info = $file->validate(['ext'=>'jpg,png,gif'])->move(WEB_static .DIRECTORY_SEPARATOR .'uploads','');
第四步:(选做)安全性!禁止目录文件被直接访问。因为你将入口文件移到了跟目录,框架下的所有目录已经暴露了。如果apache服务器没处理。那就可以直接访问重要文件。于是不管三七二十一,不管他有没有做处理,直接跟目录下的每个目录都来个.htaccess,然后写入deny from all(第一级目录操作即可)。起码安心点。另,bug可能在等着你,如Linux下的文件路径大小写敏感的等等。最后,可用“百度云观测”测试网站安全性能。

8、thinkphp5 连接 sqlite数据库得配置方法
(检查你PHP.ini文件中的extension=php_pdo_sqlite.dll )
对于使用 Sqlite 作为数据库的,有这4个设置就足以。
<?php
// ThinkPHP Sqlite 数据库配置
return [
'type' => 'sqlite',
'database' => './db/dev.s3db', // 相对于入口文件的数据库文件路径
'prefix' => 'prefix_',
'debug' => true
];

9、thinkphp怎么跳转页面:
同一控制器(controller)的不同方法之间的跳转:
$this->success('提示信息','方法名')
$this->redirect('方法名',delay,'提示信息')
$this->error('提示信息','方法名')
不同控制器里方法的跳转:$this->redirect('控制器/方法名',delay,'提示信息')
不同分组之间的跳转:$this->redirect('Admin-Index/index',delay,'提示信息')
注意:/为左斜杠非右斜杠,这是thinkphp配置中默认的设置符号。
附 :history.back(-1)和history.go(-1)的区别:history.back(-1)//后退+刷新,直接返回当前页的上一页,数据全部消息,是个新页面,history.go(-1)//后退,也是返回当前页的上一页,不过表单里的数据全部还在。可能经常在使用history.back或go(-1)时会显示网页已过期:解决办法:一、在要返回的目标页面中,添加<%response.setHeader(“cache-control”,”private”); %>二、将目标页面的form的method=”post”去掉,或改为method=”get”。(tp中基本上不会用以上两种处理方法,一般是直接跳转到另个网页)

10、验证器:
我们在写网站和软件交互的时候,通常有js的判断。但就是我在前端JS已经做了些判断,比如什么内容不能为空,邮箱格式是否错误。那我为啥还需要在后端的时候,还需要写一个验证器呢,大概是两点:  
1.前端的判断,是为了更友好的交互,但后端的验证是为了数据库的安全,不受被攻击。比如,精通编程的人,会直接绕过前端的验证,来对后端直接访问。
2.我们会接受客户端传来的参数,这些个参数是不可信的,我们后端开发人员必须对这个参数进行验证。
ThinkPHP5.1完全开发手册中的“验证”中的“内置规则”:
https://www.kancloud.cn/manual/thinkphp5_1/354107
TP5验证规则系统内置的验证规则如下:
格式验证类require  验证某个字段必须,例如:'name'=>'require'
number 或者 integer  验证某个字段的值是否为数字(采用filter_var验证),例如:'num'=>'number'
float  验证某个字段的值是否为浮点数字(采用filter_var验证),例如:'num'=>'float'
boolean  验证某个字段的值是否为布尔值(采用filter_var验证),例如:'num'=>'boolean'
email  验证某个字段的值是否为email地址(采用filter_var验证),例如:'email'=>'email'
array  验证某个字段的值是否为数组,例如:'info'=>'array'
accepted  验证某个字段是否为为 yes, on, 或是 1。这在确认"服务条款"是否同意时很有用,例如:'accept'=>'accepted'
date  验证值是否为有效的日期,例如:'date'=>'date'
注:会对日期值进行strtotime后进行判断。
alpha  验证某个字段的值是否为字母,例如:'name'=>'alpha'
alphaNum  验证某个字段的值是否为字母和数字,例如:'name'=>'alphaNum'
alphaDash  验证某个字段的值是否为字母和数字,下划线_及破折号-,例如:'name'=>'alphaDash'
activeUrl  验证某个字段的值是否为有效的域名或者IP,例如:'host'=>'activeUrl'
url  验证某个字段的值是否为有效的URL地址(采用filter_var验证),例如:'url'=>'url'
ip  验证某个字段的值是否为有效的IP地址(采用filter_var验证),例如:'ip'=>'ip'
注:支持验证ipv4和ipv6格式的IP地址。
dateFormat:format  验证某个字段的值是否为指定格式的日期,例如:'create_time'=>'dateFormat:y-m-d'
长度和区间验证类in  验证某个字段的值是否在某个范围,例如:'num'=>'in:1,2,3'
notIn  验证某个字段的值不在某个范围,例如:'num'=>'notIn:1,2,3'
between  验证某个字段的值是否在某个区间,例如:'num'=>'between:1,10'
notBetween  验证某个字段的值不在某个范围,例如:'num'=>'notBetween:1,10'
length:num1,num2  验证某个字段的值的长度是否在某个范围,例如:'name'=>'length:4,25' 或者指定长度 'name'=>'length:4'
如果验证的数据是数组,则判断数组的长度。如果验证的数据是File对象,则判断文件的大小。
max:number  验证某个字段的值的最大长度,例如:'name'=>'max:25'
如果验证的数据是数组,则判断数组的长度。如果验证的数据是File对象,则判断文件的大小。
min:number  验证某个字段的值的最小长度,例如:'name'=>'min:5'
如果验证的数据是数组,则判断数组的长度。如果验证的数据是File对象,则判断文件的大小。
after:日期  验证某个字段的值是否在某个日期之后,例如:'begin_time' => 'after:2016-3-18',
before:日期  验证某个字段的值是否在某个日期之前,例如:'end_time' => 'before:2016-10-01',
expire:开始时间,结束时间  验证当前操作(注意不是某个值)是否在某个有效日期之内,例如:'expire_time' => 'expire:2016-2-1,2016-10-01',
allowIp:allow1,allow2,...  验证当前请求的IP是否在某个范围,例如:'name' => 'allowIp:114.45.4.55',
注:该规则可以用于某个后台的访问权限
denyIp:allow1,allow2,...  验证当前请求的IP是否禁止访问,例如:'name' => 'denyIp:114.45.4.55',
字段比较类confirm  验证某个字段是否和另外一个字段的值一致,例如:'repassport'=>'require|confirm:passport'
different  验证某个字段是否和另外一个字段的值不一致,例如:'name'=>'require|different:account'
egt 或者 >=  验证是否大于等于某个值,例如:'score'=>'egt:60' || 'num'=>'>=:100'
gt 或者 >  验证是否大于某个值,例如:'score'=>'gt:60' || 'num'=>'>:100'
elt 或者 <=  验证是否小于等于某个值,例如:'score'=>'elt:100' || 'num'=>'<=:100'
lt 或者 <  验证是否小于某个值,例如:'score'=>'lt:100'|| 'num'=>'<:100'
eq 或者 = 或者 same  验证是否等于某个值,例如:'score'=>'eq:100'|| 'num'=>'=:100'|| 'num'=>'same:100'
filter验证  支持使用filter_var进行验证,例如:'ip'=>'filter:validate_ip'
正则验证  支持直接使用正则验证,例如:'zip'=>'\d{6}'  或者  'zip'=>'regex:\d{6}',
如果你的正则表达式中包含有|符号的话,必须使用数组方式定义。
'accepted'=>['regex'=>'/(yes|on|1)$/i'],  也可以实现预定义正则表达式后直接调用,例如:
上传验证file  验证是否是一个上传文件
image:width,height,type  验证是否是一个图像文件,width height和type都是可选,width和height必须同时定义。
fileExt:允许的文件后缀  验证上传文件后缀
fileMime:允许的文件类型  验证上传文件类型
fileSize:允许的文件字节大小  验证上传文件大小
行为验证  使用行为验证数据,例如:'data'=>'behavior:\app\index\behavior\Check'
其它验证unique:table,field,except,pk  验证当前请求的字段值是否为唯一的,例如:
// 表示验证name字段的值是否在user表(不包含前缀)中唯一  'name' => 'unique:user',  // 验证其他字段  'name' => 'unique:user,account',  // 排除某个主键值  'name' => 'unique:user,account,10',  // 指定某个主键值排除  'name' => 'unique:user,account,10,user_id',  如果需要对复杂的条件验证唯一,可以使用下面的方式:
// 多个字段验证唯一验证条件  'name' => 'unique:user,statusaccount',  // 复杂验证条件  'name' => 'unique:user,status=1&account='.$data['account'],requireIf:field,value  验证某个字段的值等于某个值的时候必须,例如:
// 当account的值等于1的时候 password必须  'password'=>'requireIf:account,1'requireWith:field  验证某个字段有值的时候必须,例如:
// 当account有值的时候password字段必须  'password'=>'requireWith:account


11、initialize() 初始化方法:
initialize() 这个方法在官方手册里是这样说的:如果你的控制器类继承了\think\Controller类的话,可以定义控制器初始化方法initialize,在该控制器的方法调用之前首先执行。

12、分页实现:
thinkphp5中要想同时获得查询记录的总数量以及分页的数据, 可以用paginate()方法, 真的非常方便!
// 查询状态为1的用户数据 并且每页显示10条数据(如是带参数的查询分页则用后面的另个方法)
$list = Db::name('user')->where('status',1)->paginate(10);
//如果是分页搜索页面则需要带上参数分页才准确
//$list = Db::name('db')->where(array('key'=>$key))->order('id DESC')->paginate(15,false,['query'=>request()->param()]);
// 把分页数据赋值给模板变量list
$this->assign('list', $list);
// 渲染模板输出
return $this->fetch();
$data = [
'total' => $r->total(), // 总记录数
'cur' => $r->currentPage(), // 当前页码
'size' => $r->listRows(), // 每页记录数
'list' => $r->items() // 分页数据
];
print_r($data);
TP5.1中利用bootstrap4中分页居中:<div class="row justify-content-center">{$list|raw}</div>
为了避免出现XSS安全问题,默认的变量输出都会使用htmlentities方法进行转义输出。
raw的意思:如果你不需要转义(例如你需要输出html表格等内容),可以使用:{$data.name|raw}
{$data.name|raw}编译后的结果是:<?php echo $data['name']; ?>
{$data.name}编译后的结果是:<?php echo htmlentities($data['name']); ?>
render()方法是 Bootstrap 类中的 render() 方法
使用paginate分页搜索带参数(get方式): $data = Db::name('db')->where(array('key'=>$key))->order('id DESC')->paginate(15,false,['query'=>request()->param()]);
//'query'=>request()->param()是获取携带的参数
注:在带有查询条件分页中,提交查询条件要用get方法,post方法无法下一页时无法查询到准确的数据

13、数据库的操作:
(1)原生查询:
设置好数据库连接信息后,我们就可以直接进行原生的SQL查询操作了,包括 query 和 execute 两个方法,分别用于查询和写入
//显示数据库列表
$result=Db::query('show tables from demo');
dump($result);
//清空数据表
$result=Db::execute('TRUNCATE table think_data');
dump($result);
query 方法用于查询,默认情况下返回的是数据集(二维数组), execute 方法的返回值是影响的行数。
实际开发中,可能某些数据使用的是外部传入的变量,为了让查询操作更加安全,我们建议使用参数绑定机 制,例如:
Db::execute('insert into think_data (id,name,status) values (?,?,?)',[8,'thinkphp',1]);
$result=Db::query('select * from think_data where id=?',[8]);
dump($result);
(2)find 方法用于查找满足条件第一个记录(即使你的查询条件有多个符合的数据),如果查询成功,返回的是一个一维数组,没有满足条件的话则默认返回 null (也支持设置是否抛出异常)。
select 方法用于查询数据集,如果查询成功,返回的是一个二维数组,如果没有满足条件的话则返回空 数组(也支持设置是否需要抛出异常)。
(3)链式操作:
使用链式操作可以完成复杂的数据库查询操作,例如:
//查询十个满足条件的数据并按照id倒序排列
$list=Db::name('data')->field('id,name')->order('id','desc')->where('status',1)->limit(10) ->select();
dump($list);
支持链式操作的查询方法包括:
select 查询数据集;find 查询单个记录;insert 插入记录 ;update 更新记录 ;delete 删除记录; value 查询值; column 查询列 ;chunk 分块查询 ;count,max,min,avg,sum等聚合查询
(4)批量查询:
我们可以使用一个方法完成多个查询条件
$result=Db::name('data')->where(['id'=>['between','1,3'],'name'=>['like','%think%'],])->select();
dump($result);
(5)thinkphp5的强大的时间查询功能:
使用where方法
// 大于某个时间
where('create_time','> time','2016-1-1');
// 小于某个时间
where('create_time','<= time','2016-1-1');
// 时间区间查询
where('create_time','between time',['2015-1-1','2016-1-1']);
第三个参数可以传入任何有效的时间表达式,会自动识别你的时间字段类型,支持的时间类型包括timestamps、datetime、date和int。
(6)数据库语句:
DB::table('表名,需要加上表前缀')或者name('表名,不需要表前缀')->where('条件如多个可用数组')->find('查询一条')或者selset('查询多条');//查询
DB::table()或者name()->where()->update('更新条件')//更新
DB::table()或者name()->where()->delete();//删除
DB::table()或者name()->insert();//添加 (添加不需要加条件只需加上表名即可)
DB::query('原生sql语句');
DB::qyert('SELECT VERSION() AS `ver`');//查询当前数据库版本 并定义别名为ver
(7)ThinkPHP5.0 查询构造器:
使用PDO参数绑定,以保护应用程序免于SQL 注入,因此传入的参数不需额外转义特殊字符。
//插入记录
Db::name('data')->insert(['id'=>18,'name'=>'thinkphp']);
//更新记录
Db::name('data')->where('id', 18)->update(['name'=>"framework"]);
//查询数据
$list=Db::name('data')->where('id',18)->select();
dump($list);
//删除数据
Db::name('data')->where('id', 18)->delete();
如果使用系统提供的助手函数 db 则可以进一步简化查询代码如下:
$db=db('data'); //插入记录
$db->insert(['id'=> 20,'name' =>'thinkphp']);
db 助手函数默认会每次重新连接数据库,因此应当尽量避免多次调用
(8)删除确认对话框的函数warning(javascript脚本):
可放在前端html文件中
function warning(info, url){
if(window.confirm(info)){
window.location.href = url;
}
}
(9)thinkphp 更新数据时如果未修改数据,返回结果判断错误的问题:
解决办法: 如果没有更新,返回的是0而不是false。有错误才会返回false,应该用严格类型判断 "==="而不能用"=="去判断。
$result = $Model->where('id=1')->save($data);
if($result !== false) {
echo 'success';
}else{
echo 'false';
}

14、cookie 和session :
大多数情况,我们不需要手动进行Session初始化操作。 ThinkPHP5 会在第一次调用 Session 类的时候按照配置的参数自动初始化和开启 Session (如果 auto_start 设置为 true 的话)。大多数情况下,我们不需要进行 Cookie 的初始化,系统会在调用 Cooie 类方法的时候自动根据 cache 配置参数初始化。
使用助手函数
session('name','thinkphp'); //赋值(当前作用域)
session('name','thinkphp','think'); //赋值think作用域
session('?name'); //判断(当前作用域)是否赋值
session('name'); //取值(当前作用域)
session('name','','think');//取值think作用域
session('name',null);//删除(当前作用域)
session(null); //清除session(当前作用域)
session(null,'think');//清除think作用域

cookie('name','value',3600); //设置
cookie('?name'); //判断cookie值是否存在
echo cookie('name'); //获取
cookie('name',null); //删除
cookie(null,'think_');//清除
注:处在“应用调试模式”('app_debug' => true)下设置的时间无效,即关闭浏览器后cookie失效

15、命名空间:
是唯一识别的一套名字,这样当对象来自不同的地方但是名字相同的时候就不会含糊不清了。不同的人写的程序不可能所有的变量都没有重名现象,为了解决同名这个问题引出的。在XML里,任何元素类别或者属性因此分为两部分名字,一个是命名空间里的名字另一个是它的本地名。

16、thinkphp中input助手函数:
(助手函数:系统为一些常用的操作方法封装了助手函数,便于使用)
input:获取输入数据 支持默认值和过滤。input助手函数是request请求的进一步封装,在代码中可以使用input助手函数拿到传输过来的值。
(https://www.kancloud.cn/manual/thinkphp5/118044)
用法如下:
input(变量类型.变量名/修饰符);
或者
Request::instance()->变量类型(变量名/修饰符);
例如:
input(' get.name/d');
input(' post.name/s');
Request::instance()->get('name/d');
注意:ThinkPHP5.0版本默认的变量修饰符是/s,如果你要获取的数据为数组,请一定注意要加上 /a 修饰符才能正确获取到。如果需要传入字符串之外的变可以使用下面的修饰符:S强制转换为字符串类型;d强制转换为整型类型;b强制转换为布尔类型;a强制转换为数组类型;f强制转换为浮点类型;
添加应用函数:如果需要给当前应用添加函数,只需要在应用的公共文件(application/common.php)中定义需要的函数即可,系统会自动加载

17、thinkPHP5中的 return: 使用 return 来返回一个html ,自动渲染到页面上
thinkphp页面跳转几种方法:
$this->success("输出的提示信息","/User/list/"); //查询成功后跳转的页面第二个参数是模板路径地址
$this->error("输出的错误信息"); //查询失败后返回上一页 
$this->redirect("Index/list"); //直接跳转,不带计时后跳转

18、thinkPHP调试用方法:
halt($member_list);//相当于dump再接下中断脚本运行
dump($stat);
在app.php中设置'app_debug' => true, 'app_trace'=>true,和database.php中设置'debug' => true,后就可在浏览器右下角tp图标中看到sql等执行的时间性能等。
thinkphp中dump()方法:
dump ThinkPHP 框架 自定义的 用作框架变量 调试用的输出 功能可以说和 var_dump一样的.dump是php原生函数var_dump和print_r升级版本哦。。var_dump和print_r是一个打印变量的相关信息函数,但是对人观看十分不友好。dump() 函数用于输出变量的相关信息。dump() 函数显示关于一个或多个表达式的结构信息,包括表达式的类型与值。数组将递归展开值,通过缩进显示其结构。如:dump($list);
调试还可用另一个函数halt($list);//输出结果并停止往下
附:如用phpstudy自带的软件mysql-front来查看数据库的话,更新等数据操作后要按软件中的刷新按钮才能看到变化。

19、关联模型中的一对一关联(关联表):
hasone('关联模型名','关联表的外键ID','当前关联表的ID');
belongTo('关联模型名','关联表的外键ID','当前关联表的ID');:
hasone与belongTo区别hasone是没有关联两个表的外键时使用,belongTo时有关联两个表的外键时
定义相对关联:
belongsTo('关联模型','外键','关联主键');
除了关联模型外,其它参数都是可选。
关联模型(必须):模型名或者模型类名
外键:当前模型外键(当前模型的关联字段),默认的外键名规则是关联模型名+_id
关联主键:关联模型主键(要关联的模型的主键),一般会自动获取也可以指定传入
如:
在文章模型中:public function cate(){ return $this->belongsTo('cate','cateid'); }//在文章模型中的cateid字段关联到栏目模型(cate)的id主键
在文章控制器中:$list = ArticleModel::paginate(15);
然后在视图中显示:
{volist name="list" id="vo"}
{$vo.title}
{$vo.cate.catename}//显示关联模型cate表中的catename字段
{/volist}
(以上语句相当于:$list=Db::name('article')->alias('a')->join('cate c','c.id=a.cateid')->field('a.id,a.title,a.pic,a.author,a.state,c.catename')->paginate(3); )
附:网上某些评论:join对数据库的查询压力要大些,少用;关联模型由thinkphp官方封装,比较灵活,对数据库的压力小,过滤了一些不安全关联的情况。
个人理解,联合查询一般用于做列表功能的多数据查询,侧重复杂的条件查询,而关联模型用于单条数据查询,这样写代码时侧重逻辑,简化查询,例如一个订单的处理,订单表关联一个用户几个商品,如果用join,会比较烦人,你需要手动写几个查询,如果其他地方又要处理订单,需要同样的数据,又得写,那么就更烦人,这时使用关联模型,就爽很多了。
Join的表不能当成主表的字段一样更新,会提示出错。
Tp的关联模型 可以把关联的表当成主表的字段一样更新。^_^
使用模型关联预加载后,在效率上高于开发者自己写join和子查询,模型关联底层是通过分别查询主体和关联数据再将它们关联匹配到一起。
实际上,thinkphp的关联模型,就是简化你的jion操作。所以,本质上,关联模型,就是处理表连接关系的。归根结底的,就是让你在用模型操作的时候,简化SQL查询的join操作。

20、thinkphp5.1常量定义使用:
thinkphp5.1取消了系统常量
可以把常量配置在app.php文件中
'ROOT_PATH' => Env::get('ROOT_PATH'),
可以使用config()函数直接取出,config('ROOT_PATH')
在模板文件中使用{$Think.config.ROOT_PATH}

21、thinkphp中的前台模板volist标签:
通常模型的select方法返回的结果是一个二维数组,可以直接使用volist标签进行输出。
Volist标签一般是和内置方法assign()搭配使用,将值从后台传到前台,是当下比较流行的一种传值方法
{volist name="list" id="vo"}详解:name(必须):要输出的数据模板变量,name='list'需要与操作中的模板赋值指定对应$list; id(必须):循环变量,可以任意指定。{}标签中默认只能输出vo数组中的元素的值,{vo.xx},在php中代表$list['xx'],{:}里面可以包含方法,方便用三元运算符判断值,例如{:isset($list[$vo.id]['title'])?$list[$vo.id]['title']:''}
属性:
name(必须):要输出的数据模板变量
id(必须):循环变量
offset(可选):要输出数据的offset
length(可选):输出数据的长度
key(可选):循环的key变量,默认值为i
mod(可选):对key值取模,默认为2
empty(可选):如果数据为空显示的字符串
通常模型的select方法返回的结果是一个二维数组,可以直接使用volist标签进行输出。
例如:
输出查询到的记录:
{volist name="list" id="vo" }
{$vo.id}
{$vo.name}
{/volist}
输出偶数记录:
{volist name="list" id="vo" mod="2" }
{eq name="mod" value="1"}{$vo.name}{/eq}
{/volist}

22、模板中使用if:
{if condition="对数据进行判断"} 输出的值
{elseif condition="$name eq 2"/}输出的值
{else /} 输出的值
{/if}

23、thinkphp中的前台模板使用原生PHP:
{php}echo 'Hello,world!';{/php}
在PHP标签里面不能再使用PHP本身不支持的代码。

24、thinkphp中的前台模板几个常见标签意思:
{$varname}模板变量
{:function(…)}执行函数并输出返回值
{~function(…)}执行函数但不输出
{/* 注释内容 */ } 或 {// 注释内容 }

25、thinkphp 模板页面select判断 if标签:
<select class="form-control" name="catetype" id="catetype" required>
<option value="软件" {if condition="$cates.catetype eq '软件'"}selected="selected"{/if}>软件</option>
<option value="文章" {if condition="$cates.catetype eq '文章'"}selected="selected"{/if}>文章</option>
<option value="网页" {if condition="$cates.catetype eq '网页'"}selected="selected"{/if}>网页</option>
</select>
<select class="form-control" name="cateid" id="cateid" required>
<option value="">请选择栏目</option>
{volist name="cateres" id="vo"}
<option {if condition="$vo['id'] eq $articles['cateid']"}selected="selected"{/if} value="{$vo.id}">{$vo.catename}</option>
{/volist}
</select>

26、前台视图模板中的图片路径问题:
我们有时候需要把开发的项目布署在二级目录中,
tp5.1:需要在根目录下的config/template.php中设置tpl_replace_string的值。这时候刷新页面看一下。发现还是__PUBLIC__并没有转义。这里是因为Runtime下面有缓存文件。把Runtime下的文件都删除再试一下。问题完美解决了。
'tpl_replace_string'=>['__PUBLIC__'=>dirname($_SERVER['SCRIPT_NAME'])==DIRECTORY_SEPARATOR?'':dirname($_SERVER['SCRIPT_NAME']),],
(DIRECTORY_SEPARATOR目录分隔符,是定义php的内置常量)
这样就使得,在未启用域名时,返回 /thinkphp5/public ,而启用域名后,返回一个空的字符串。 然后我们这样改写V层:
<link rel="stylesheet" type="text/css" href="__PUBLIC__/static/bootstrap-3. 3.5-dist/css/bootstrap.min.css">

27、volist循环实现分类及文章嵌套输出
(https://beltxman.com/1451.html)
public function alist()
{
$cates=db::name('cate')->where(array('catetype'=>'文章'))->field('id,catename')->order('catesort asc')->select();//查询文章类型栏目对应的id
foreach ($cates as $k => $v) {
$articlelist[$k]["catename"]=$v['catename'];
$articlelist[$k]["child"]=db::name('article')->where(array('cateid'=>$v['id']))->field('id,title,cateid')->order("tsort asc")->select();//数组中的数组(二维数组),实现分类及文章嵌套输出
}
$this->assign(array(
'articlelist'=>$articlelist,
));
return $this->fetch();
}

二、其它php相关知识摘录
1、PHP单引号与双引号:
(1)在php中,大多数情况下,单引号与双引号的作用是相同的。但有些人说,单引号的执行效率更高。当然,事 实也是这样,但高出的效率可以忽略不计。但既然有人这样说了,我们推荐在输出字符时,使用单引号。 (2)在一些HTML混写时,我们需要单引号与双引号结合进行使用。在进行文件写入时,我们必须使用双引号,否 则比如字符中的 \r\n 不会被替换为换行符。 3、其它情况下,我们推荐使用单引号。

2、PHP数组里面的某一个字段值相加(求和):(PHP 5.5及以上才有的函数)
(1)使用数组函数:array_column() 返回输入数组中某个单一列的值
(2)使用数组求和函数:array_sum() 返回数组中值的和
(3)echo array_sum(array_column($your_array, 'money'));

3、PHP中的=>,->,::是什么意思:
->是对象执行方法或取得属性用的。如$a->add();
=>是数组里键和值对应用的。如$a = array('0' => '1','2' => '4',); echo $a['0'];echo $a['2'];
::双冒号操作符即作用域限定操作符,可以访问静态、const和类中重写的属性与方法。
php中的“::”是调用类中的静态方法或者常量,属性的符号。使用非静态方法,要先创建实例如$obj = new aaa();$obj -> br();,使用静态方法(static function),无需创建实例,直接使用类名如aaa::ar();“=>” 是数组中用于数组的 key 和 value之间的关系;“->”是用于引用类实例的方法和属性。

4、php中的&表示什么呢?
给这个方法传递变量的引用,类似c中的指针一样,传递的时变量的内存地址。这样,next方法内部就会直接操作传递过去的array变量。不带引用,就相当于给了一份拷贝,原本的值是不变的。

5、$this 一定是在class 类的内部才会出现的一个PHP的关键字,表示当前对象,一般是当前类调用自己的属性和方法。
(加$this是类里的方法,不加是框架文件Common目录下functions.php里的方法)

6、empty 和 isset 的区别:
empty检查一个变量是否为空。当var存在,并且是一个非空非零的值时返回 FALSE 否则返回 TRUE。以下的东西被认为是空的:"" (空字符串),0 (作为整数的0),0.0 (作为浮点数的0),"0" (作为字符串的0),NULL,FALS,Earray() (一个空数组),$var; (一个声明了,但是没有值的变量)
isset判断变量是否已存在。0、00、’0′、』、’ ‘、false、’false’、’null’都返回true,只有值為null的变量返回false。is_null 判断变量是否为NULL

7、php 三元运算符 echo不是函数的问题:
$a==true ? print "yes" : print "no";//这个运行正常,
$a==true ? echo "yes" : echo "no"; //这个会报错,
echo $a==true ? "yes" : "no"; // 这样也可以的。
echo 是语言结构,和 if else一样,而 print是函数,和 substr()这样的函数一样。语言结构的处理效率要高于函数。echo是语言结构, print和print_r是函数,语句没有返回值,函数可以有返回值(即便没有用)。

8、同一页面,不同的表单,name值相同会有问题吗:
不同表单的name值相同,如果你用的是表单提交就没有问题。
但是需要注意:如果你用ajax提交,使用jquery单独获取每个输入表单的值,通过name属性取值的话,会因为存在name属性同名的表单,可能取值会弄混。

9、input中name和id的区别:
id 一般是给前端使用的(方便js找到这个标签);name 一般是后台使用的(如果表单提交上去就可以再后台的返回值找到name这个属性)
ID就像是一个人的身份证号码,而Name就像是他的名字,ID显然是唯一的,而Name是可以重复的。name与id的还有区别是:
  id要符合标识的要求,比如大小写敏感,最好不要包含下划线(因为不兼容CSS)。而name基本上没有什么要求,甚至可以用数字。
  补充:name主要是表单元素里才有的属性。通过js的document.表单名称.文本框.value来获取文本框的值,其中的表单名称和文本框名称指的是name,而非表单元素例如div,span等是没有name属性的,而id属性是任何一个HTML元素都会有的。当你需要用js获取非表单元素对象是就得用document.getElementByIdx("id")
   name在以下用途是不能替代的:
(1)表单(form)的控件名,提交的数据都用控件的name而不是id来控制。因为有许多name会同时对应多个控件,比如checkbox和radio, 而id必须是全文档中唯一的。此外浏览器会根据name来设定发送到服务器的request。因此如果用id,服务器是无法得到数据的。
(2)frame和window的名字,用于在其他frame或window指定target。
  以下两者可以通用,但是强烈建议用id不要用name:
(1)锚点,通常以前写作<a name="myname">,现在可以用任何的元素id来指定:<div id="myid">。
  以下情况只能用id:
(1) label与form控件的关联,
<label for="MyInput">My Input</label>
<input id="MyInput" type="text">
for属性指定与label关联的元素的id,不可用name替代。
(2) CSS的元素选择机制,以#MyId的方式指定应用样式的元素,不能用name替代。
(3)脚本中获得对象:
IE支持在脚本中直接以id(而不是name)引用该id标识的对象。例如上面的input,要在脚本中获得输入的内容,可以直接以MyInput.value来获得。
如果用DOM的话,则用document.getElementById("MyInput").value,如果要用name的话,通常先得到包含控件的form,例如document.forms[0],然后从form再引用name,注意这样得到的是经过计算后将发送给服务器的值。

10、php中的foreach:
这只是一种遍历数组简便方法。foreach 仅能用于数组。有两种语法,第二种比较次要但却是第一种的有用的扩展。
foreach (array_expression as $value)
statement
foreach (array_expression as $key => $value) //foreach(数组名 as 下标=>值)
statement
第一种格式遍历给定的 array_expression 数组。每次循环中,当前单元的值被赋给 $value 并且数组内部的指针向前移一步(因此下一次循环中将会得到下一个单元)。
第二种格式做同样的事,只是除了当前单元的键名也会在每次循环中被赋给变量 $key。第二种格式除了能像第一种格式一样得到数组内元素的值外,还能得到元素的索引值,并保存到$key变量中。
例1:
$myArray=array("1"=>"val1","2"=>"val2","3"=>"val3");
foreach($myArray as $val) {
print($val." ");
}
其结果会输出:val1 val2 val3
例2:
$a = array( "one" => 1, "two" => 2, "three" => 3,"seventeen" => 17);
foreach ($a as $k => $v) {
echo "<pre>";
echo "[$k] => $v\n";
}
结果:
[one] => 1
[two] => 2
[three] => 3
[seventeen] => 17
解说:k其实指的就是key,v其实指的就是value
总结:foreach在PHP项目中使用频繁,尤其是在处理数组时!

11、php中相对路径和绝对路径:
(1)php中好像不能像asp那样用“/”表示根目录,代之以$_SERVER['DOCUMENT_ROOT'],其它则相同:../表示向上一层。./表示当前层。
(2)dirname('__FILE__')和$_SERVER['DOCUMENT_ROOT']是表示根目录,这个根目录是绝对路径,但是会随着你的项目移动而变化,所以可以多用。这种绝对路径

12、Web开发中的相对路径和绝对路径:
在学习HTML的时候一定会遇到引入文件和链接跳转页面,比如:JS文件、CSS文件、Image图片。我们就会考虑是相对路径和绝对路径的问题。下面PHP程序员雷雪松就详细讲解下Web开发中的相对路径和绝对路径是什么?
相对路径,就是相对于当前文件的目标文件位置。这样有个好处就是,当你整个项目移动时,你项目内文件之间的相对关系没有改变,你之前设置的路径任然是准确的。例如:Web服务器文件夹a下面有index.html和image.jpg两个文件。index.html文件里引入image.jpg,只要这两个文件的相对位置没有变(也就是说还是在文件夹a下面),那么无论上传到Web服务器的哪个位置,这个路径都是正确的。在相对路径里面,./表示同级目录,../表示上级目录。
绝对路径是指目录下的绝对位置,直接到达目标位置。比如:d:/www/index.html、https://www.leixuesong.cn/index.php。使用绝对路径可以防止网站被恶意抄袭,抄袭默认的链接还是指向自己的网站。只要页面中的目标文件位置不变你的链接还是指向正确的URL。在Web开发的时候一般很少使用绝对路径,因为你本地的环境和服务器上的路径可能不一样。/表示文件的根目录。
在Web开发中的相对路径和绝对路径都有使用,各有优劣。简单的总结下,相对路径就是以当前文件为参考点,来确定不同文件的路径,相对路径一般会以./、../开始,当然.如果文件是同级目录./可以省略绝对路径就是以计算机的文件或者是网络上的绝对地址确定文件的路径,绝对路径一般是Windows下的盘符开始、Linux下的/开始(但是在Web服务器中,/表示Web服务器的根目录)、或者是以网址开始。

13、关于javascript:
javascript和java是不同公司开发的,是不一样的。java主要在服务端运行,javascript主要运行在客户端浏览器中。JavaScript注释写法:1.多行注释:/* 这里写上要注释的东西*/;2.单行注释://要单独写在一行中,和其它符号写在一行(如{后加//注释)则脚本就不能被正确解释运行了
<!DOCTYPE html>:<!doctype html>是html5标准网页声明,声明必须是 HTML 文档的第一行

14、html中的role:
<form role="form">
role本质上是增强语义性,增强组件的可访问性、可用性和可交,是一个html5的属性,role="form"告诉辅助设备(如屏幕阅读器)这个元素所扮演的角色是个表单,在button中role="button"就是告诉设备,这是个按钮,可以点击。

15、mysql软删除和硬删除
https://www.jianshu.com/p/889365078e24
硬删除不多解释
为什么要用到软删除
有后悔药可以恢复数据。但是同时带来弊端。导致 查数据时 慢 尤其是一些特殊场景下。
目前 软删除的做法
在表内加 isDeleted bool
在表内添加 deleted_at timestamp (可以为null) (gem gorm这类orm框架支持)
将删除数据 存储到 因为一个表内 (看过一些软件是这样实现的,感觉效率高,开发稍微费事点)
第2种 方式 其实是最差的。因为 可以为null 导致 查询效率大打折扣。更重要的情况 会导致 全表扫描 如果数据量偏大千万不要贪图方便就是这要搞了,这类导致查询的性能瓶颈我在2个项目都有遇到过。
设计软删除原则
考虑是否 一定需要软删除 (不需要最好不要画蛇添足)
考虑数据业务量,读 和 写的 比例
读条件 针对 where 条件复杂 并且 业务量 1w条以上的 建议不要使用第2种方案 可以考虑使用第3种方案

16、路径中使用斜杠/和反斜杠\的区别
https://blog.51cto.com/dldxzjr/2395709
Unix使用斜杆/ 作为路径分隔符,而web应用最新使用在Unix系统上面
所以目前所有的网络地址都采用 斜杆/ 作为分隔符。
Windows由于使用 斜杆/ 作为DOS命令提示符的参数标志了,为了不混淆,所以采用 反斜杠\ 作为路径分隔符。
所以目前windows系统上的文件浏览器都是用 反斜杠\ 作为路径分隔符。随着发展,DOS系统已经被淘汰了,命令提示符也用的很少,斜杆和反斜杠在大多数情况下可以互换,没有影响。
知道这个背景后,可以总结一下结论:
(1)浏览器地址栏网址使用 斜杆/ ;
(2)windows文件浏览器上使用 反斜杠\ ;
(3)出现在html url() 属性中的路径,指定的路径是网络路径,所以必须用 斜杆/ ;
<div style=' background-image:url(/Image/Control/title.jpg); background-repeat:repeat-x; padding:10px;'' ></div>
// 如果url后面用反斜杠,就不会显示任何背景
(4)出现在普通字符串中的路径,如果代表的是windows文件路径,则使用 斜杆/ 和 反斜杠\ 是一样的;
如果代表的是网络文件路径,则必须使用 斜杆/ ;
<img src='.\Image/Control/ding.jpg' /> // 本地文件路径,/ 和 \ 是等效的
<img src="./Image\Control\cai.jpg" />
<img src="http://hiphotos.baidu.com/yuhua522/pic/item/01a949c67e1023549c163df2.jpg" />
// 网络文件路径,一定要使用 斜杆/

猜你喜欢

转载自www.cnblogs.com/cmwjr/p/12764707.html