首页
归档
朋友
关于我
留言
【Wiki知识库】
Search
1
虚拟机无法ping不通百度,并无法访问浏览器
4,586 阅读
2
mysql使用or条件使索引失效
3,618 阅读
3
mysql如何在一对多查询时选取时间最近的一条记录
2,972 阅读
4
根据MySQL获取当天,昨天,本周,本月,上周,上月,本月的起始时间
2,432 阅读
5
git常用命令大全
1,600 阅读
PHP
面向对象
设计模式
知识汇总
常用函数
PHP框架知识
数据库
MySQL
服务器
Docker
虚拟机
Nginx
缓存相关
Redis
前端
中间件
RabbitMQ
网络编程
HTTP相关
Swoole
Workerman
工具软件
Git
Typecho
杂乱无章
面试指南
PHP相关
MySQL面试汇总
中间件相关
开发技巧 | 优化
Search
标签搜索
php
mysql
代码片段
linux
Thinkphp
Redis
nginx
mysql优化
docker
面试指南
面向对象
git
Laravel框架
http协议
RabbitMQ
Redis性能优化
设计模式
linux命令
编译安装
PhpSpreadsheet
黎明强
累计撰写
70
篇文章
累计收到
58
条评论
首页
栏目
PHP
面向对象
设计模式
知识汇总
常用函数
PHP框架知识
数据库
MySQL
服务器
Docker
虚拟机
Nginx
缓存相关
Redis
前端
中间件
RabbitMQ
网络编程
HTTP相关
Swoole
Workerman
工具软件
Git
Typecho
杂乱无章
面试指南
PHP相关
MySQL面试汇总
中间件相关
开发技巧 | 优化
页面
归档
朋友
关于我
留言
搜索到
5
篇与
Thinkphp
的结果
2022-10-15
ThinkPHP5源码分析(1) : 类的自动加载
前文Composer 下载ThinkPHP5.1的源码,每个框架它都必须都有一个“类的自动加载”机制 ,我们都知道PHP引入文件是需要require 、 include 才能使用别的类文件中的方法。比如我需要写一个公共文件 model.phpinclude "model.php" include "model2.php" class User { //code.. }但是!如何当公共类库文件很多的时候,每次都需要手动引入,就显得非常麻烦,不利于/不方便维护管理。所以PHP引入了一个spl_autoload_register() 的类自动加载,TP框架就是借助了 spl_autoload_register() 来完成类的自动加载。TP5框架入口加载机制学习框架源码的第一步,先找到入口文件 public/index.php ,然后一步步跟进流程,看下代码执行的过程。第一行:定义命名空间就不赘述了。。第二行:去加载基础文件 base.php ,是位于上一层目录的 think目录下打开Base.php ,第16行就会去加载 Loader.php 文件 (就是TP5自动加载的类库) ,Loader.php 是TP5封装的底层基础类库。再引用了核心文件 Loader.php 调用类库的 Loader::register() 的方法发现都用了spl_autoload_register()的系统函数,其他框架也是同理。 都是会在框架的第一步“入门文件”就进行类的自动加载机制,针对底层进行封装。TP5中的Loader::register() 其实做了2件事:内部自定义一个autoload() 去进行框架的底层深度封装为了支持 Composer 自动加载 安装第三方的类库插件(Vendor),都是遵循PSR-4的风格统一,那么加载composer类的 autoload_static.php 后,再去加载对应的插件类库。分析Loader::register的执行流程如下截图:分析TP5执行 Loader::register() 的注册自动加载方法 ,( 是调用不存在的类的时候才会执行spl_autoload_register())运用3元运算符,如果有参数就执行其他自定义类,没就 加载本类的autoload() 方法调用 self::gerRootPath() 获取项目的根目录这里就是走 Composer的加载机制,然后组织一个Vendor的决定路径 ,self::$composerPath判断是否有Vendor的目录,再判断是否有auto_static的文件 ,有就加载composer目录下的auto_static.php分析Composer自动加载——类文件在逻辑往下走,判断是否有Vendor的目录,再判断是否有auto_static的文件 ,有就加载composer目录下的auto_static.phpauto_static.php发现定义了2个属性分别是: $prefixLengthsPsr4 、$prefixDirsPsr4 ,这是什么意思呢?定义数组,有个key和value,比如 $prefixLengthsPsr4 (PSR4的长度)t key代表一个命名空间 ,代表think\composer\ 命名空间 ,首字母代表类,把某些类放进去来,15 代表字符的长度。a key也是代表一个命名空间,代表:app ,用首字母代表,把某些类放进去, 4是这个字符的长度。2个斜线是转义字符,比如 think\\composer\\ 等同于 think\composer\$prefixDirsPsr4 把每个命名空间的类对应的目录列出来比如think\composer 这个命名空间 在src下app\\ 这个命名空间就在根目录的application比如通过 Compsoe r安装 swoole、workermam、phpexcel 就把相应的规则追加数组上 填进来。总结: composer的统一加载机制的地方,每次composer新类库的时候,都会往这个属性追加 命名空间 以及类库的目录路径 。分析Composer自动加载——属性赋值回到Loader::register()方法。// Composer自动加载支持 if (is_dir(self::$composerPath)) { if (is_file(self::$composerPath . 'autoload_static.php')) { require self::$composerPath . 'autoload_static.php'; $declaredClass = get_declared_classes(); $composerClass = array_pop($declaredClass); foreach (['prefixLengthsPsr4', 'prefixDirsPsr4', 'fallbackDirsPsr4', 'prefixesPsr0', 'fallbackDirsPsr0', 'classMap', 'files'] as $attr) { if (property_exists($composerClass, $attr)) { self::${$attr} = $composerClass::${$attr}; } } } else { self::registerComposerLoader(self::$composerPath); } } // 注册命名空间定义 self::addNamespace([ 'think' => __DIR__, 'traits' => dirname(__DIR__) . DIRECTORY_SEPARATOR . 'traits', ]);再返回 Loader::register() 方法接着放下分析:如果存在Vendor目录,再判断是否有 composer_static.php ,有就执行如下:执行了 get_declared_classes 这个系统函数,返回由当前脚本中已定义类的名字组成的数组。我们打印这个get_declared_classes得到目前所有加载的类,最后require加载的是 composer类。所以,我们上面的 array_pop 弹出最后一个元素,赋值后的 $composerClass ,就是composer的类。这个命令空间那么长的其实就是 composer目录下的autoload_static.php再继续往下执行property_exists : 检查对象或类是否具有该属性我们知道autoload_static.php 存在有prefixLengthsPsr4$prefixDirsPsr4$classMap等一众的方法,composer的 stacis.php这些属性以及值 ,再赋值作为Loader类的某个属性再处理。上面的写法等同 :self::prefixLengthsPsr4 self::prefixDirsPsr4打印这些属性返回:为什么这样去做?后续要集合多个属性再Map,加载文件的时候用这些属性。总结: 把composere下的auto_static的PSR4的属性以及值赋值到Loader的PSR4属性中分析Composer自动加载——注册命名空间会调用当前Loader::addNamespace() 方法 ,把当前think 跟traits 核心注册进行。// 注册命名空间定义 self::addNamespace([ 'think' => __DIR__, 'traits' => dirname(__DIR__) . DIRECTORY_SEPARATOR . 'traits', ]);进去 addNamespace() 方法,我们打印这个 $namespace 参数。// 注册命名空间 public static function addNamespace($namespace, $path = '') { echo "<pre>"; print_r($namespace);exit; if (is_array($namespace)) { foreach ($namespace as $prefix => $paths) { self::addPsr4($prefix . '\\', rtrim($paths, DIRECTORY_SEPARATOR), true); } } else { self::addPsr4($namespace . '\\', rtrim($path, DIRECTORY_SEPARATOR), true); } }再接下来,无论是不是数组,都再把命名空间拼接组装好,再调用self::addPsr4()查看 addPsr4() 方法注册的时候走的是“296” 行 。因为之前 self::$prefixDirsPsr4 里的属性只是composer的autp_static.php 上的,只有 think\ 跟 app\ ,并没有think 跟traits 这2个属性。public static $prefixDirsPsr4 = array ( 'think\\composer\\' => array ( 0 => __DIR__ . '/..' . '/topthink/think-installer/src', ), 'app\\' => array ( 0 => __DIR__ . '/../..' . '/application', ), );这样就完成 think、traits下的命名空间注册到Loader类的PSR4属性中。加载类库映射文件再往下执行我们在根目录的runtime 并没有classmap.php的文件 ,我们可以通过命令生成这个文件php think optimize:autoload这时候runtime下就有classmap.php ,就是存放一些命名空间映射的文件<?php /** * 类库映射 */ return [ 'app\\index\\controller\\Index' => '/Users/limingqiang/project_php/localhost_pro/tp51_source_code/application/' . 'index/controller/Index.php', 'think\\App' => '/Users/limingqiang/project_php/localhost_pro/tp51_source_code/thinkphp/library/' . '/think/App.php', 'think\\Build' => '/Users/limingqiang/project_php/localhost_pro/tp51_source_code/thinkphp/library/' . '/think/Build.php', 'think\\Cache' => '/Users/limingqiang/project_php/localhost_pro/tp51_source_code/thinkphp/library/' . '/think/Cache.php', 'think\\Collection' => '/Users/limingqiang/project_php/localhost_pro/tp51_source_code/thinkphp/library/' . '/think/Collection.php', 'think\\Config' => '/Users/limingqiang/project_php/localhost_pro/tp51_source_code/thinkphp/library/' . '/think/Config.php', 'think\\Console' => '/Users/limingqiang/project_php/localhost_pro/tp51_source_code/thinkphp/library/' . '/think/Console.php', 'think\\Container' => '/Users/limingqiang/project_php/localhost_pro/tp51_source_code/thinkphp/library/' . '/think/Container.php', //code..... ]进入这个 self::addClassMap() 方法,看到把当前classmap.php的数组内容赋值到一个 Loader类的$classMap 属性中。总结: 把tp5的核心的 think 和 traits 命名空间注册到PSR4里,方便后续调用,实在属性多个数组统一自动加载。自动加载extend目录再往下执行进去 self::addAutoLoadDir() 方法: // 注册自动加载类库目录 public static function addAutoLoadDir($path) { self::$fallbackDirsPsr4[] = $path; }把当前extend的目录也加载到 Loader类 $fallbackDirsPsr4 的属性中。总结prefixDirsPsr4 (对应类的目录)prefixLengthsPsr4 (对应类的命名长度)fallbackDirsPsr4 (对应extend的目录)我们拿到很多变量成员、命令空间、目录路径等都赋值到 Loader类的多个PSR4的属性中。后续再拿这些属性做自动加载配置。
2022年10月15日
98 阅读
1 评论
0 点赞
2021-07-17
一文带你熟悉TP5.1的模型各种操作
前文带你熟悉TP5.1中的模型获取器、修改器、模型搜索器、模型数据集、模型自动时间戳、模型只读字段、模型转换器、模型范围搜索等..01. 模型获取器和修改器本节课我们来学习模型中操作比较方便的获取器和修改器。一. 模型获取器获取器的作用是对模型实例的数据做出自动处理;一个获取器对应模型的一个特殊方法,该方法为 public;方法名的命名规范为:getFieldAttr() ;举个例子,数据库表示状态 status 字段采用的是数值;而页面上,我们需要输出 status 字段希望是中文,就可以使用获取器;在 User 模型端,我创建一个对外的方法,如下:public function getStatusAttr($value) { $status = [-1=>'删除', 0=>'禁用', 1=>'正常', 2=>'待审核']; return $status[$value]; }然后,在控制器端,直接输出数据库字段的值即可得到获取器转换的对应值$user = UserModel::get(21); return $user->status;除了 getFieldAttr 中 Field 可以是字段值,也可以是自定义的虚拟字段;public function getNothingAttr($value, $data) { $myGet = [-1=>'删除', 0=>'禁用', 1=>'正常', 2=>'待审核']; return $myGet[$data['status']]; } return $user->nothing;Nothing 这个字段不存在,而此时参数$value 只是为了占位,并未使用;第二个参数$data 得到的是筛选到的数据,然后得到最终值;如果你定义了获取器,并且想获取原始值,可以使用 getData() 方法;return $user->getData('status');直接输出无参数的 getData(),可以得到原始值,而$user 输出是改变后的;dump($user->getData()); //获取原始值 dump($user); //获取改变后的值使用 WithAttr 在控制器端实现动态获取器,比如设置所有 email 为大写;$result = UserModel::WithAttr('email', function ($value) { return strtoupper($value); })->select(); return json($result);使用 WithAttr 在控制器端实现动态获取器,比如设置 status 翻译为中文;result = UserModel::WithAttr('status', function ($value) { $status = [-1=>'删除', 0=>'禁用', 1=>'正常', 2=>'待审核']; return $status[$value]; })->select(); return json($result);. 同时定义了模型获取器和动态获取器,那么模型修改器优先级更高二. 模型修改器模型修改器的作用,就是对模型设置对象的值进行处理;比如,我们要新增数据的时候,对数据就行格式化、过滤、转换等处理;模型修改器的命名规则为:setFieldAttr ;我们要设置一个新增,规定邮箱的英文都必须大写,修改器如下:public function setEmailAttr($value) { return strtoupper($value); }除了新增,会调用修改器,修改更新也会触发修改器;模型修改器只对模型方法有效,调用数据库的方法是无效的,比如->insert();02. 模型搜索器和数据集本节课我们来学习模型中的用于封装的搜索器和数据结果集的操作。一. 模型搜索器搜索器是用于封装字段(或搜索标识)的查询表达式;一个搜索器对应模型的一个特殊方法,该方法为 public;方法名的命名规范为:searchFieldNameAttr();举个例子,我们要封装一个邮箱字符模糊查询,然后封装一个时间限定查询;在 User 模型端,我创建两个对外的方法,如下://邮箱查询 public function searchEmailAttr($query, $value) { $query->where('email', 'like', $value.'%'); } //时间查询 public function searchCreateTimeAttr($query, $value) { $query->whereBetweenTime('create_time', $value[0], $value[1]); }然后,在控制器端,通过 withSearch() 静态方法实现模型搜索器的调用**;$result = UserModel::withSearch(['email', 'create_time'],[ 'email' => 'xiao', 'create_time' => ['2014-1-1', '2017-1-1'] ])->select();withSearch() 中第一个数组参数,限定搜索器的字段,第二个则是表达式值;如果想在搜索器查询的基础上再增加查询条件,直接使用链式查询即可;UserModel::withSearch(...)->where('gender', '女')->select()如果你想在搜索器添加一个可以排序的功能,具体如下://model层 public function searchEmailAttr($query, $value, $data) { $query->where('email', 'like', $value.'%'); if (isset($data['sort'])) { $query->order($data['sort']); } } //controller调用 $result = UserModel::withSearch(['email', 'create_time'],[ 'email' => 'xiao', 'create_time' => ['2014-1-1', '2017-1-1'], 'sort' => ['price'=>'desc'] ])->select();搜索器的第三个参数$data,可以得到 withSearch()方法第二参数的值;字段也可以设置别名:'create_time'=>'ctime'一. 模型数据集数据集由 all() 和 select() 方法返回数据集对象;数据集对象和数组操作方法一样,循环遍历、删除元素等;判断数据集是否为空,我们需要采用 isEmpty() 方法$resut = UserModel::where('id', 111)->select(); if ($resut->isEmpty()) { return '没有数据!'; }使用模型方法 hidden() 可以隐藏某个字段,使用 visible() 显示只某个字段使用 append() 可以添加某个获取器字段,使用 withAttr() 对字段进行函数处理;$result = UserModel::select(); $result->hidden(['password'])->append(['nothing'])->withAttr('email', function ($value) { return strtoupper($value); }); return json($result);使用模型方法 filter() 对筛选的数据进行过滤;$result = UserModel::select()->filter(function ($data) { return $data['price'] > 100; }); return json($result);也可以使用数据集之后链接 where()方法来代替 filter()方法;$result = UserModel::select()->where('price', '>', '100');数据集甚至还可以使用 order() 方法进行排序;$result = UserModel::select()->order('price', 'desc');使用 diff() 和 intersect()方法可以计算两个数据集的差集和交集;$result1 = UserModel::where('price', '>', '80')->select(); $result2 = UserModel::where('price', '<', '100')->select(); return json($result1->diff($result2)); return json($result2->intersect($result1)); 03. 模型自动时间戳和只读字段本节课我们来学习模型中用于记录时间的自动时间戳和不可更改只读字段。一. 模型自动时间戳系统自动创建和更新时间戳功能默认是关闭状态;如果你想全局开启,在 database.php 中,设置为 true;// 自动写入时间戳字段 'auto_timestamp' => true,如果你只想设置某一个模型开启,需要设置特有字段;class User extends Model { //开启自动时间戳 protected $autoWriteTimestamp = true; }当然,还有一种方法,就是全局开启,单独关闭某个或某几个模型为 false;自动时间戳开启后,会自动写入 create_time 和 update_time 两个字段;此时,它们的默认的类型是 int,如果是时间类型,可以更改如下:'auto_timestamp' => 'datetime', //或 protected $autoWriteTimestamp = 'datetime';都配置完毕后,当我们新增一条数据时,无须新增 create_time 会自动写入时间;同理,当我们修改一条数据时,无须修改 update_time 会自动更新时间;自动时间戳只能在模型下有效,数据库方法不可以使用;如果创建和修改时间戳不是默认定义的,也可以自定义;protected $createTime = 'create_at'; protected $updateTime = 'update_at';如果业务中只需要 create_time 而不需要 update_time,可以关闭它;protected $updateTime = false;也可以动态实现不修改 update_time,具体如下:$user->isAutoWriteTimestamp(false)->save();二. 模型只读字段模型中可以设置只读字段,就是无法被修改的字段设置;我们要设置 username 和 email 不允许被修改,如下:protected $readonly = ['username', 'email'];除了在模型端设置,也可以动态设置只读字段;$user->readonly(['username', 'email'])->save();同样,只读字段只支持模型方式不支持数据库方式;04. 模型类型转换和数据完成本节课我们来学习模型中字段的类型转换和数据操作的自动完成。一. 模型类型转换系统可以通过模型端设置写入或读取时对字段类型进行转换;我们这里,通过读取的方式来演示部分效果;在模型端设置你想要类型转换的字段属性,属性值为数组;protected $type = [ 'price' => 'integer', 'status' => 'boolean', 'create_time' => 'datetime:Y-m-d' ];数据库查询读取的字段很多都是字符串类型,我们可以转换成如下类型:integer(整型)、float(浮点型)、boolean(布尔型)、array(数组) object(对象)、se由于数据库没有那么多类型演示,常用度不显著,我们提供几个方便演示的;public function typeConversion() { $user = UserModel::get(21); var_dump($user->price); var_dump($user->status); var_dump($user->create_time); }需要注意的是: 类型转换还是会调用属性里的获取器等操作,编码时要注意这方面的问题;三. 模型数据完成模型中数据完成通过 auto、insert 和 update 三种形式完成;auto 表示新增和修改操作,insert 只表示新增,update 只表示修改;protected $auto = ['email']; protected $insert = ['uid'=>1]; protected $update = [];先理解insert,当我们新增一条数据时会触发新增数据完成;此时,并不需要自己去新增 uid,它会自动给 uid 赋值为 1;$user = new UserModel(); $user->username = '李白'; $user->password = '123'; $user->gender = '男'; $user->email = 'libai@163.com'; $user->price = 100; $user->details = '123'; $user->save();auto 表示新增和修改均要自动完成,而不给默认值的字段需要修改器提供;public function setEmailAttr($value) { return strtoupper($value); }新增时,邮箱字符串会被修改器自动完成大写,那数据完成的意义何在?修改时,如果你不去修改邮箱,在数据自动完成强制完成,会自动完成大写;也就是说,邮箱的大写,设置 update 更加合适,因为新增必填必然触发修改器;对于 update 自动完成,和 auto、insert 雷同,自行演示;05. 模型查询范围和输出本节课我们来学习模型中封装查询范围的方法以及模型对外输出的方式。一. 模型查询范围在模型端创建一个封装的查询或写入方法,方便控制器端等调用**;比如,封装一个筛选所有性别为男的查询,并且只显示部分字段 5 条;方法名规范:前缀 scope,后缀随意,调用时直接把后缀作为参数使用;public function scopeGenderMale($query) { $query->where('gender', '男')->field('id,username,gender,email')->limit(5); }在控制器端,我们我们直接调用并输出结果即可;public function queryScope() { $result = UserModel::scope('gendermale')->select(); //$result = UserModel::gendermale()->select(); return json($result); }也可以实现多个查询封装方法连缀调用,比如找出邮箱 xiao 并大于 80 分的;public function scopeEmailLike($query, $value) { $query->where('email', 'like', '%'.$value.'%'); } public function scopePriceGreater($query, $value) { $query->where('price', '>', 80); } //调用 $result = UserModel::emailLike('xiao')->priceGreater(80)->select();查询范围只能使用 find() 和 select()两种方法;全局范围查询,就是在此模型下不管怎么查询都会加上全局条件;//全局范围查询 protected function base($query) { $query->where('status', 1); }在定义了全局查询后,如果某些不需要全局查询可以使用 useGlobalScope 取消;UserModel::useGlobalScope(false)当然,设置为 true,则开启全局范围查询,注意:这个方法需要跟在::后面;UserModel::useGlobalScope(true)二. 模型输出方式通过模版进行数据输出;public function view() { $user = UserModel::get(21); $this->assign('user', $user); return $this->fetch(); }根据错误提示,可以创建相对应的模版,然后进行数据显示;{$user.username}. {$user.gender}. {$user.email}使用 toArray()方法,将对象按照数组的方式输出;$user = UserModel::get(21); print_r($user->toArray());和之前的数据集一样,它也支持 hidden、append、visible 等方法;print_r($user->hidden(['password,update_time'])->toArray());toArray() 方法也支持 all()和 select()等列表数据;print_r(UserModel::select()->toArray());使用 toJson() 方法将数据对象进行序列化操作,也支持 hidden 等方法;print_r($user->toJson());
2021年07月17日
878 阅读
1 评论
0 点赞
2021-07-17
ThinkPHP5.1中各种表达式查询
01. 查询表达式本节课我们要学习查询中的几种查询方式:比较查询、区间查询、其它查询等。一. 比较查询在查询数据进行筛选时,我们采用 where() 方法,比如 id=80;Db::name('user')->where('id', 80)->find(); //where(字段名,查询条件) Db::name('user')->where('id','=',80)->find(); //where(字段名,表达式,查询条件)其中,表达式不区分大小写,包括了比较、区间和时间三种类型的查询;使用<>、>、<、>=、<= 可以筛选出各种符合比较值的数据列表;Db::name('user')->where('id','<>',80)->select();二. 区间查询使用like 表达式进行模糊查询;Db::name('user')->where('email','like','xiao%')->select();like 表达式还可以支持数组传递进行模糊查询;Db::name('user')->where('email','like',['xiao%','wu%'], 'or')->select(); //SELECT * FROM `tp_user` WHERE (`email` LIKE 'xiao%' OR `email` LIKE 'wu%')like 表达式具有两个快捷方式 whereLike() 和 whereNoLike();Db::name('user')->whereLike('email','xiao%')->select(); Db::name('user')->whereNotLike('email','xiao%')->select();between 表达式具有两个快捷方式 whereBetween() 和 whereNotBetween() ;Db::name('user')->where('id','between','19,25')->select(); Db::name('user')->where('id','between',[19, 25])->select(); Db::name('user')->whereBetween('id',[19, 25])->select(); Db::name('user')->whereNotBetween('id',[19, 25])->select();in 表达式具有两个快捷方式 whereIn()和 whereNotIn();Db::name('user')->where('id','in', '19,21,29')->select(); Db::name('user')->whereIn('id','19,21,29')->select(); Db::name('user')->whereNotIn('id','19,21,29')->select();null 表达式具有两个快捷方式 whereNull()和 whereNotNull() ;Db::name('user')->where('uid','null')->select(); Db::name('user')->where('uid','not null')->select(); Db::name('user')->whereNull('uid')->select(); Db::name('user')->whereNotNull('uid')->select();三. 其他查询使用 exp 可以自定义字段后的 SQL 语句;Db::name('user')->where('id','exp','IN (19,21,25)')->select(); Db::name('user')->whereExp('id','IN (19,21,25)')->select();02. 时间查询本节课我们要单独学习一下时间的所有查询方式,包括传统式、快捷方式和固定查询等。一. 传统方式可以使用>、<、>=、<= 来筛选匹配时间的数据Db::name('user')->where('create_time', '> time', '2018-1-1')->select();可以使用 between 关键字来设置时间的区间;Db::name('user')->where('create_time', 'between time', ['2018-1-1','2019-12-31'])->select(); Db::name('user')->where('create_time', 'not between time', ['2018-1-1','2019-12-31'])->select();二. 快捷方式时间查询的快捷方法为 whereTime() ,直接使用>、<、>=、<=;Db::name('user')->whereTime('create_time', '>', '2018-1-1')->select();快捷方式也可以使用 between 和 not between;Db::name('user')->whereBetween('create_time', ['2018-1-1','2019-12-31'])->select();还有一种快捷方式为:whereBetweenTime() ,如果只有一个参数就表示一天;Db::name('user')->whereBetweenTime('create_time', '2018-1-1','2019-12-31')->select(). 默认的大于>,可以省略;Db::name('user')->whereTime('create_time', '2018-1-1')->select();三. 固定查询关键词说明today 或 d今天yesterday昨天week 或者 w本周last week上周month 或者 m本月last month 或者m上月year 或者 y今年last year去年Db::name('user')->whereTime('create_time','d')->select(); Db::name('user')->whereTime('create_time','y')->select();四. 其他查询查询指定时间的数据,比如两小时内的;Db::name('user')->whereTime('create_time', '-2 hour')->select();查询两个时间字段时间有效期的数据,比如会员开始到结束的期间;Db::name('user')->whereBetweenTimeField('start_time','end_time')->select();03. 聚合、原生和子查询本节课我们来学习三种查询方式:包括聚合查询、子查询和原生查询。一. 聚合查询使用 count() 方法,可以求出所查询数据的数量;Db::name('user')->count();count() 可设置指定 id,比如有空值(Null)的 uid,不会计算数量;Db::name('user')->count('uid');使用 max() 方法,求出所查询数据字段的最大值;Db::name('user')->max('price');如果 max() 方法,求出的值不是数值,则通过第二参数强制转换;Db::name('user')->max('price', false);使用 min() 方法,求出所查询数据字段的最小值,也可以强制转换;Db::name('user')->min('price');使用 avg() 方法,求出所查询数据字段的平均值Db::name('user')->avg('price');使用 sum() 方法,求出所查询数据字段的总和Db::name('user')->sum('price');二. 子查询使用 fetchSql() 方法,可以设置不执行 SQL,而返回 SQLDb::name('user')->fetchSql(true)->select();使用 buidSql() 方法,也是返回 SQL 语句,但不需要再执行 select(),且有括号;Db::name('user')->buildSql(true);结合以上方法,我们实现一个子查询;#one过滤找出所有男性的信息 $subQuery = Db::name('two')->field('uid')->where('gender','男')->buildSql(true); $result = Db::name('one')->where('id','exp','IN '.$subQuery)->select();使用闭包的方式执行子查询;$result = Db::name('one')->where('id', 'in', function ($query) { $query->name('two')->where('gender', '男')->field('uid'); })->select();三. 原生查询使用 query() 方法,进行原生 SQL 查询,适用于读取操作,SQL 错误返回 false;Db::query('select * from tp_user');使用 execute 方法,进行原生 SQL 更新写入等,SQL 错误返回 false;Db::execute('update tp_user set username="孙悟空" where id=29');
2021年07月17日
593 阅读
1 评论
0 点赞
2021-07-17
ThinkPHP5.1的模型中常用的CURD操作
01 模型定义本节课我们来学习模型篇章中的定义方法,设置以及一些基本的操作。一. 定义模型定义一个和数据库表向匹配的模型;class User extends Model模型会自动对应数据表,并且有一套自己的命名规则模型类需要去除表前缀(tp_),采用驼峰式命名,并且首字母大写tp_user(表名) => User tp_user_type(表名) => UserType如果担心设置的模型类名和 PHP 关键字冲突,可以开启应用类后缀;在 app.php 中,设置class_suffix 属性为 true 即可;// 应用类库后缀 'class_suffix' => true,设置完毕后,所有的控制器类名和模型类名需要加上 Controller 和 Model;class UserModel二. 设置模型默认主键为 id,你可以设置其它主键,比如 uid;protected $pk = 'uid';从控制器端调用模型操作,如果和控制器类名重复,可以设置别名use app\model\User as UserModel;在模型定义中,可以设置其它的数据表;protected $table = 'tp_one';模型和控制器一样,也有初始化,在这里必须设置 static 静态方法;//模型初始化 protected static function init() { //第一次实例化的时候执行 init echo '初始化 User 模型'; }三. 模型操作模型操作数据和数据库操作一样,只不过不需要指定表了;UserModel::select();数据库操作返回的列表是一个二维数组,而模型操作返回的是一个结果集;[[]] 和 [{}]02. 模型中的增删改查本节课我们来学习模型中的修改和查询、删除、添加操作。一. 数据添加使用实例化的方式添加一条数据,首先实例化方式如下,两种均可:$user = new UserModel(); $user = new \app\model\User();设置要新增的数据,然后用 save() 方法写入到数据库中,save()返回布尔值$user->username = '李白'; $user->password = '123'; $user->gender = '男'; $user->email = 'libai@163.com'; $user->price = 100; $user->details = '123'; $user->uid = 1011; $user->create_time = date('Y-m-d H:i:s'); $user->save();也可以通过 save() 传递数据数组的方式,来新增数据;$user = new UserModel(); $user->save([ 'username' => '李白', 'password' => '123', 'gender' => '男', 'email' => 'libai@163.com', 'price' => 100, 'details' => '123', 'uid' => 1011, 'create_time' => date('Y-m-d H:i:s') ]);模型新增也提供了 replace() 方法来实现 REPLACE into 新增;$user->replace()->save();当新增成功后,使用$user->id ,可以获得自增 ID(主键需是 id);echo $user->id;使用 saveAll() 方法,可以批量新增数据,返回批量新增的数组;$dataAll = [ [ 'username' => '李白 1', 'password' => '123', 'gender' => '男', 'email' => 'libai@163.com', 'price' => 100, 'details' => '123', 'uid' => 1011, 'create_time' => date('Y-m-d H:i:s') ], [ 'username' => '李白 2', 'password' => '123', 'gender' => '男', 'email' => 'libai@163.com', 'price' => 100, 'details' => '123', 'uid' => 1011, 'create_time' => date('Y-m-d H:i:s') ] ]; $user = new UserModel(); print_r($user->saveAll($dataAll));二. 数据删除使用 get() 方法,通过主键(id)查询到想要删除的数据$user = UserModel::get(93);然后再通过 delete() 方法,将数据删除,返回布尔值;$user->delete();也可以使用静态方法调用 destroy() 方法,通过主键(id)删除数据;UserModel::destroy(92)静态方法 destroy()方法,也可以批量删除数据UserModel::destroy('80, 90, 91'); UserModel::destroy([80, 90, 91]);通过数据库类的查询条件删除;UserModel::where('id', '>', 80)->delete();使用闭包的方式进行删除;UserModel::destroy(function ($query) { $query->where('id', '>', 80); });三. 数据修改使用 get() 方法通过主键获取数据,然后通过 save()方法保存修改,返回布尔值;$user = UserModel::get(118); $user->username = '李黑'; $user->email = 'lihei@163.com'; $user->save();通过 where() 方法结合 find() 方法的查询条件获取的数据,进行修改;$user = UserModel::where('username', '李黑')->find(); $user->username = '李白'; $user->email = 'libai@163.com'; $user->save();save()方法只会更新变化的数据,如果提交的修改数据没有变化,则不更新;但如果你想强制更新数据,即使数据一样,那么可以使用 force() 方法;$user->force()->save();Db::raw() 执行SQL 函数的方式,同样在这里有效;$user->price = Db::raw('price+1');如果只是单纯的增减数据修改,可以使用 inc/dec;$user->price = ['inc', 1];直接通过 save([],[]) 两个数组参数的方式更新数据;$user->save([ 'username' => '李黑', 'email' => 'lihei@163.com' ],['id'=>118]);通过saveAll() 方法,可以批量修改数据,返回被修改的数据集合;$list = [ ['id'=>118, 'username'=>'李白', 'email'=>'libai@163.com'], ['id'=>128, 'username'=>'李白', 'email'=>'libai@163.com'], ['id'=>129, 'username'=>'李白', 'email'=>'libai@163.com'] ]; $user->saveAll($list);批量更新 saveAll() 只能通过主键 id 进行更新使用静态方法结合 update() 方法来更新数据,这里返回的是影响行数UserModel::where('id', 118)->update([ 'username' => '李黑', 'email' => 'lihei@163.com' ]);另外一种静态方法 update(),返回的是对象实例;UserModel::update([ 'id' => 118, 'username' => '李黑', 'email' => 'lihei@163.com' ]);模型的新增和修改都是 save()进行执行的 ,它采用了自动识别体系来完成;实例化模型后调用 save()方法表示新增 ,查询数据后调用 save()表示修改;当然,如果在 save() 传入更新修改条件后也表示修改;再当然,如果编写的代码比较复杂的话,可以用 isUpdate() 方法显示操作;//显示更新 $user->isUpdate(true)->save(); //显示新增 $user->isUpdate(false)->save();四. 数据查询使用 get() 方法,通过主键(id)查询到想要的数据;$user = UserModel::get(129); return json($user);也可以使用 ·where()· 方法进行条件筛选查询数据$user = UserModel::where('username', '辉夜')->find(); return json($user);不管是get() 方法还是 find() 方法,如果数据不存在则返回 Null;和数据库查询一样,模型也有 getOrFail() 方法,数据不存在抛出异常;同上,还有 findOrEmpty() 方法,数据不存在返回空模型;通过模型->符号,可以得到单独的字段数据;return $user->username;如果在模型内部获取数据,请不要用$this->username,而用如下方法;public function getUserName() { return self::where('username', '辉夜')->find()->getAttr('username'); }通过 all() 方法,实现 IN 模式的多数据获取;$user = UserModel::all('79, 118, 128'); $user = UserModel::all([79, 118, 128]);使用链式查询得到想要的数据;UserModel::where('gender', '男')->order('id', 'asc')->limit(2)->select();获取某个字段或者某个列的值;UserModel::where('id', 79)->value('username'); //某个字段 UserModel::whereIn('id',[79,118,128])->column('username','id'); //某个列的值模型支持动态查询:getBy *,* 表示字段名UserModel::getByUsername('辉夜'); UserModel::getByEmail('huiye@163.com');模型支持聚合查询;UserModel::max('price');
2021年07月17日
594 阅读
2 评论
1 点赞
2021-07-17
ThinkPHP5.1的常用增删改查操作
增删改查的操作学习一下数据库 Db 类的查询语句,包含 table、name 以及助手函数 db。学习来源于李炎恢TP5讲义一. 新增数据使用 insert() 方法可以向数据表添加一条数据;$data = [ 'username' => '辉夜', 'password' => '123', 'gender' => '女', 'email' => 'huiye@163.com', 'price' => 90, 'details' => '123', 'create_time' => date('Y-m-d H:i:s') ]; Db::name('user')->insert($data);如果新增成功,insert() 方法会返回一个 1 值$flag = Db::name('user')->insert($data); if ($flag) return '新增成功!';你可以使用 data() 方法来设置添加的数据数组;Db::name('user')->data($data)->insert();如果你添加一个不存在的数据,会抛出一个异常 Exception;如果采用的是 mysql 数据库,支持 REPLACE 写入 ;Db::name('user')->insert($data, true);使用 insertGetId() 方法,可以在新增成功后返回当前数据 ID;Db::name('user')->insertGetId($data);使用 insertAll() 方法,可以批量新增数据,但要保持数组结构一致$data = [ [ 'username' => '辉夜 1', 'password' => '123', 'gender' => '女', 'email' => 'huiye@163.com', 'price' => 90, 'details' => 123, 'create_time' => date('Y-m-d H:i:s') ], [ 'username' => '辉夜 2', 'password' => '123', 'gender' => '女', 'email' => 'huiye@163.com', 'price' => 90, 'details' => 123, 'create_time' => date('Y-m-d H:i:s') ], ]; Db::name('user')->insertAll($data);批量新增也支持 data()方法,和单独新增类似;Db::name('user')->data($data)->insertAll()批量新增也支持 reaplce 写入,和单独新增类似;Db::name('user')->insertAll($data, true);二. 修改数据使用 update() 方法来修改数据,修改成功返回影响行数,没有修改返回0$data = [ 'username' => '李白' ]; $update = Db::name('user')->where('id', 38)->update($data); return $update;或者使用 data() 方法传入要修改的数组,如果两边都传入会合并;Db::name('user')->where('id', 38)->data($data)->update(['password'=>'456']);如果修改数组中包含主键,那么可以直接修改;(不需要写where()链式 )$data = [ 'username' => '李白', 'id' => 38 ]; Db::name('user')->update($data);使用 inc() 方法可以对字段增值, dec() 方法可以对字段减值;Db::name('user')->inc('price',3)->update($data); //price+3块, Db::name('user')->dec('price', 3)->update($data); //price减3块增值和减值如果同时对一个字段操作,前面一个会失效;Db::name('user')->inc('price')->dec('price', 3)->update($data); //只把price减3使用 exp() 方法可以在字段中使用 mysql 函数;Db::name('user')->exp('email', 'UPPER(email)')->update($data); //邮箱转大写使用 raw() 方法修改更新,更加容易方便$data = [ 'username' => '李白', 'email' => Db::raw('UPPER(email)'), 'price' => Db::raw('price - 3'), 'id' => 38 ]; Db::name('user')->update($data);使用 setField() 方法可以更新一个字段值;Db::name('user')->where('id', 38)->setField('username', '辉夜');增值 setInc() 和减值 setDec() 也有简单的做法,方便更新一个字段值Db::name('user')->where('id', 38)->setInc('price');增值和减值如果不指定第二个参数,则步长默认为 1;三. 删除数据极简删除delete() 可以根据主键直接删除,删除成功返回影响行数,否则 0;Db::name('user')->delete(51);根据主键,还可以删除多条记录;Db::name('user')->delete([48,49,50]);正常情况下,通过 where() 方法来删除;Db::name('user')->where('id', 47)->delete();通过 true 参数删除数据表所有数据,我还没测试,大家自行测试下;Db::name('user')->delete(true);四. 查询数据Db::table() 中 table 必须指定完整数据表(包括前缀);如果希望只查询一条数据,可以使用 find()方法;Db::table('tp_user')->find();Db::getLastSql() 方法,可以得到最近一条 SQL 查询的原生语句;SELECT * FROM `tp_user` LIMIT 1想指定数据查询,可以使用 where() 方法; 没有查询到任何值,则返回 null;Db::table('tp_user')->where('id', 27)->find() //SELECT * FROM `tp_user` WHERE `id` = 27 LIMIT 1使用 findOrFail() 方法同样可以查询一条数据,在没有数据时抛出一个异常;Db::table('tp_user')->where('id', 1)->findOrFail()使用 findOrEmpty() 方法也可以查询一条数据,但在没有数据时返回一个空数组;Db::table('tp_user')->where('id', 1)->findOrEmpty();想要获取多列数据,可以使用 select() 方法;Db::table('tp_user')->select(); //SELECT * FROM `tp_user`多列数据在查询不到任何数据时返回空数组,使用 selectOrFail() 抛出异常;Db::table('tp_user')->where('id', 1)->selectOrFail();当在数据库配置文件中设置了前缀,那么我们可以使用 name() 方法忽略前缀;Db::name('user')->selectOrFail();五. 更多方法ThinkPHP 提供了一个助手函数 db,可以更方便的查询;\db('user')->select();通过 value() 方法,可以查询指定字段的值(单个),没有数据返回 null;Db::name('user')->where('id', 27)->value('username');通过 colunm() 方法,可以查询指定列的值(多个),没有数据返回空数组;Db::name('user')->column('username'); //返回多行数据colunm() 方法 ,可以指定 id 作为列值的索引;Db::name('user')->column('username', 'id'); // array( array(1=>'小明') , array(2=>'小强'))数据分批处理、大批数据处理和 JSON 数据查询,当遇到具体问题再探讨;
2021年07月17日
292 阅读
0 评论
0 点赞