首页
归档
朋友
关于我
留言
Search
1
虚拟机无法ping不通百度,并无法访问浏览器
4,847 阅读
2
mysql使用or条件使索引失效
4,061 阅读
3
mysql如何在一对多查询时选取时间最近的一条记录
3,475 阅读
4
根据MySQL获取当天,昨天,本周,本月,上周,上月,本月的起始时间
2,927 阅读
5
熟悉mysql的共享锁、排它锁、悲观锁、乐观锁以及使用场景
1,766 阅读
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
篇文章
累计收到
59
条评论
首页
栏目
PHP
面向对象
设计模式
知识汇总
常用函数
PHP框架知识
数据库
MySQL
服务器
Docker
虚拟机
Nginx
缓存相关
Redis
前端
中间件
RabbitMQ
网络编程
HTTP相关
Swoole
Workerman
工具软件
Git
Typecho
杂乱无章
面试指南
PHP相关
MySQL面试汇总
中间件相关
开发技巧 | 优化
页面
归档
朋友
关于我
留言
搜索到
11
篇与
知识汇总
的结果
2022-04-18
整理PHP7版本特性
PHP7版本特性详解原文作者:Zhengkx转自链接:https://learnku.com/articles/35800版权声明:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请保留以上作者信息和原文链接。php7.0官网手册地址 : http://php.net/manual/zh/migration70.new-features.phpphp7.1官网手册地址:http://php.net/manual/zh/migration71.new-features.phpphp7.4官网手册地址: http://php.net/manual/zh/migration74.new-features.phpPHP7.0特性标量类型声明标量 类型声明 有两种模式:强制(默认) 和 严格模式 。现在可以使用:字符串、整数、浮点数、布尔值。她们扩充了 PHP5 中引入的其他类型:类名、接口、数组和回调类型。<?php function sumOfInts(int ...$ints) { return array_sum($ints); } var_dump(sumOfInts(2, '3', 4.1)); ### 输出 int(9)返回值类型声明PHP7 增加了对返回类型声明的支持。指明了函数返回值的类型。<?php function arraysSum(array ...$arrays): array { return array_map(function (array $array): int { return array_sum($array); }, $arrays); } print_r(arraysSum([1, 2, 3], [4, 5, 6])); ### 输出 Array ( [0] => 6 [1] => 15 )null 合并运算符日常使用中存在大量同时使用三元表达式和 isset() 的情况,PHP7 添加了 null 合并运算符(??) 。如果变量存在且值不为 NULL ,它就会返回自身的值,否则返回他的第二个操作数<?php $username = $_GET['user'] ?? 'nobody'; echo $username; ##### 输出 nobody太空船操作符(组合比较符)太空船操作符用于比较两个表达式。当 $a 小于、等于或者大于 $b 时他分别返回 -1、0 或 1。<?php # 整数 echo 1 <=> 2; // -1 echo 1 <=> 1; // 0 echo 2 <=> 1; // 1 # 浮点数 echo 1.5 <=> 2.5; // -1 echo 1.5 <=> 1.5; // 0 echo 2.5 <=> 1.5; // 1 # 整数 echo "a" <=> "b"; // -1 echo "a" <=> "a"; // 0 echo "b" <=> "a"; // 1通过 define () 定义常量数组Array 类型的常量现在可以通过 define() 来定义。在 PHP 5.6 中仅能通过 const 定义<?php define('ANIMALS', [ 'dog', 'cat', 'bird' ]); echo ANIMALS[2]; ### 输出 birdClosure::call()Closure::call() 有着更好的性能,剪短干练的暂时绑定一个方法到对象上闭包并调用它。<?php class A { private $x = 1; } // PHP 7 之前版本的代码 $getXCB = function () { return $this->x; }; $getX = $getXCB->bindTo(new A, 'A'); // 中间层闭包 // PHP 7+ $getX = function() { return $this->x; }; echo $getx->call(new A);为 unserialize () 提供过滤这个特性旨在提供更安全的方式解包不可靠的数据。他通过白名单的方式来防止潜在的代码注入。预期预期 是向后兼用并增强之前的 assert() 的方法。它使得在生产环境中启用断言为零成本,并提供断言失败时抛出特定异常的能力。<?php ini_set('assert.exception', 1); class CustomError extends AssertionError() {} assert(false, new CustonError('some error message'));命名空间分组 (Group use declarations)在 PHP 7 之前,开发者经常这么做:use Universe\Saiyan; use Universe\SuperSaiyan;从同一个 namespace 导入的类、函数和常量现在可以通过单个 use 语句一次性导入。<?php use some\namespace\{ClassA, ClassB, ClassC as C}; use function some\namespace\{fn_a, fn_b, fn_c}; use const some\namespace\{ConstA, ConstB, ConstC};函数和常量也是一样的。如果它们属于同一命名空间,则可以对它们进行分组。整数除法函数 intdiv ()新加的函数 intdiv() 用来进行整数的除法运算<?php var_dump(intdiv(10, 3)); ### 输出 int(3)会话选项session_start() 可以接受一个 array 作为参数,用来覆盖 php.ini 文件中设置的会话配置选项。CSPRNG Functions新加入两个跨平台的函数:random_bytes() 和 random_int() 用来产生高安全级别的随机字符串和随机整数。<?php $bty = random_bytes(4); var_dump(bin2hex($bty)); $ints = random_int(1, 1000); var_dump($ints); ### 输出 string(8) "093a14a4" int(746)bin2hex() - 函数把包含数据的二进制字符串转换为十六进制值可以使用 list () 函数来展开实现了 ArrayAccess 接口的对象PHP7.1特性可为空(Nullable)类型参数以及返回值的类型现在可以通过在类型前加上一个问号使之允许为空。当启用这个特性时,传入的参数或者函数返回的结果要么是给定的类型,要么是 null。<?php function testReturn(): ?string { return 'elePhPant'; } var_dump(testReturn()); function testReturn1(): ?string { return null; } var_dump(testReturn1()); function test(?string $name) { var_dump($name); } test('elePHPant'); test(null); test(); ### 输出 string(9) "elePhPant" NULL string(9) "elePHPant" NULL PHP Fatal error: Uncaught ArgumentCountError: Too few arguments to function test(), 0 passedvoid 函数一个新的返回值类型 void 被引入。返回值声明为 void 类型的方法要么干脆省去 return 语句,要么使用一个空的 return 语句。对于 void 函数来说,NULL 不是一个合法的返回值List操作 (Symmetric array destructuring)短数组语法([])现在作为 list() 语法的一个备选项,可以用于将数组的值赋给一些变量(包括在 foreach 中)。<?php $data = [ [1, 'Tom'], [2, 'Fred'] ]; // 使用 list() list($id1, $name1) = $data[0]; foreach($data as list($ids, $name)) { } // 使用 [] [$id1, $name1] = $data[0]; foreach($data as [$id, $name]) { }类常量可见性现在起支持设置类常量的可见性。<?php class ConstDemo { const PUBLIC_CONST_A = 1; public const PUBLIC_CONST_B = 2; protected const PROTECTED_CONST = 3; private const PRIVATE_CONST = 4; }可见性有助于确保不应该被覆盖的内容不会被覆盖。在 PHP 7.1 之前,对于类常量(始终是公共的)来说是不可能的。list () 现在支持键名现在 list() 和它的新的 [] 语法支持在它内部指定键名。多异常捕获处理一个 catch 语句块现在可以通过管道字符 (/)来实现多个异常的捕获。<?php try { } catch (FirstException | SecondException $e) { }支持为负的字符串偏移量现在所有支持偏移量的 字符串操作函数 都支持接收负数作为偏移量,包括通过 [] 或 {} 操作字符串下标。在这种情况下,一个负数的偏移量会被理解为一个从字符串结尾开始的偏移量<?php var_dump("abcdef"[-2]); var_dump(strpos("aabbcc", 'b', -3)); ### 输出 string(1) "e" int(3)PHP7.2新特性新的对象类型这种新的对象类型,object ,引进了可用于 逆变( contravariant )参数输入和 协变(covariant)返回任务对象类型。<?php function test(object $obj) :object { return new SqlQueue(); } test(new StdClass());通过名称加载扩展扩展文件不再需要通过文件加载进行指定。可以在 php.ini 配置文件进行启用,也可以使用 dl() 函数进行启用。<?php if (!extension_loaded('sqlite')) { if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { dl('php_sqlite.dll'); } else { dl('sqlite.so'); } } 允许重写抽象方法(Abstract method)当一个抽象类继承于另外一个抽象类的时候,继承后的抽象类可以重写被继承的抽象类的抽象方法。<?php abstract class A { abstract function test(string $s); } abstract class B extends A { abstract function test($s) :int; }使用 Argon2 算法生成密码散列暴露出来的常量PASSWORD_ARGON2IPASSWORD_ARGON2_DEFAULT_MEMORY_COSTPASSWORD_ARGON2_DEFAULT_TIME_COSTPASSWORD_ARGON2_DEFAULT_THREADS新增 ext/PDO (PDO 扩展)字符串扩展类型扩展的常量PDO::PARAM_STR_NATLPDO::PARAM_STR_CHARPDO::ATTR_DEFAULT_STR_PARAM为 ext/PDO 新增额外的模拟调试信息ext/PDP (LDAP 扩展)支持新的操作方式暴露的函数和常量ldap_parse_exop()ldap_exop()ldap_exop_passwd()ldap_exop_whoami()LDAP_EXOP_START_TLSLDAP_EXOP_MODIFY_PASSWDLDAP_EXOP_REFRESHLDAP_EXOP_WHO_AM_ILDAP_EXOP_TURNext/sockets(sockets 扩展)添加了地址信息添加的函数socket_addrinfo_lookup()socket_addrinfo_connect()socket_addrinfo_bind()socket_addrinfo_explain()允许分组命名空间的尾部逗号<?php use Foo\Bar\{ Foo, Bar, Baz, }PHP7.3特性取数组第一个/ 最后一个键从 PHP 7.3 开始,你可以很容易地得到数组的第一个键和最后一个键:$array = [ 'v' => 1, 'i' => 2, 'p' => 3 ]; $firstKey = array_key_first($array); $lastKey = array_key_last($array); print_r($firstKey); // v print_r($lastKey); // p真的很简单,因为它不影响内部数组指针。PHP7.4特性数组延展操作符数组延展操作符 (PHP 7.4) 该特性可以实现以下功能:$abc = range('a', 'c'); $def = range('d', 'f'); $ghi = range('g', 'i'); $all = [...$abc, ...$def, ...$ghi, 'j']; print_r($all);返回:Array ( [0] => a [1] => b [2] => c [3] => d [4] => e [5] => f [6] => g [7] => h [8] => i [9] => j )在大多数情况下,它基本取代了array_merge().箭头函数箭头函数 (PHP 7.4)请注意,因为现在它指的是只有一个表达式的短闭包(因此有了 “短” 这个字):$c = 3; $addC = fn($x) => $x + $c; echo $addC(70); // 73不需要use关键字。空合并运算符赋值<?php $array['key'] ??= computeDefault(); // 等同于以下旧写法 if (!isset($array['key'])) { $array['key'] = computeDefault(); } ?>数组展开操作<?php $parts = ['apple', 'pear']; $fruits = ['banana', 'orange', ...$parts, 'watermelon']; // ['banana', 'orange', 'apple', 'pear', 'watermelon']; ?>
2022年04月18日
232 阅读
0 评论
0 点赞
2022-04-17
整理PHP各个版本的特性以及区别
PHP各个版本的官网: PHP文档这里只列出大概的概要特性,具体的细节以及用法可以查看官网版本文档。PHP5.2特性支持jsonPHP5.3特性新增魔术方法、命名空间、const、三元运算符添加了命名空间的支持添加了静态晚绑定支持添加了跳标签支持添加了原生的闭包(Lambda/匿名函数)支持新增了两个魔术方法, __callStatic 和 __invoke添加了 Nowdoc 语法支持, 类似于 Heredoc 语法, 但是包含单引号使用 Heredoc 来初始化静态变量和类属性/常量变为可能可使用双引号声明 Heredoc, 补充了 Nowdoc 语法可在类外部使用 const 关键词声明 常量三元运算操作符有了简写形式: ?:HTTP 流包裹器将从 200 到 399 全部的状态码都视为成功。动态访问静态方法变为可能异常可以被内嵌新增了循环引用的垃圾回收器并且默认是开启的mail() 现在支持邮件发送日志. (注意: 仅支持通过该函数发送的邮件.)PHP5.4特性数组简写 []、 Traits新增支持 traits 。新增短数组语法,比如 $a = [1, 2, 3, 4];* 或 *$a = ['one' => 1, 'two' => 2, 'three' => 3, 'four' => 4];新增支持对函数返回数组的成员访问解析,例如 foo()[0] 。现在 闭包 支持 $this 。现在不管是否设置 short_open_tag php.ini选项,<?= 将总是可用。新增在实例化时访问类成员,例如: (new Foo)->bar() 。现在支持 Class::{expr}() 语法。新增二进制直接量,例如:0b001001101 。改进解析错误信息和不兼容参数的警告。SESSION 扩展现在能追踪文件的 上传进度 。内置用于开发的 CLI 模式的 web server 。PHP5.5 特性yield迭代器、生成器(foreach)--读取大文件时减少内存foreach 现在支持 list()PHP5.6特性常量增强、可变函数、命名空间增强使用表达式定义常量。使用 ** 进行运算大文件上传 (现在支持大于2G的上传)php://input 是可重用的pgsql 异步支持PHP7.0特性PHP5.6.X到PHP7版本改动比较大的一个阶段版本。官网地址 :http://php.net/manual/zh/migration70.new-features.php标量类型声明返回值类型声明null合并运算符、太空船操作符(组合比较符)通过define()定义常量数组命名空间分组匿名类PHP7.1 特性官网地址 :http://php.net/manual/zh/migration71.new-features.php可空(Nullable)类型list简写、指定keyconst常量可指定权限多异常捕获处理(一个catch)PHP7.2特性新的对象类型 【 逆变( contravariant )参数输入和 协变(covariant)】通过名称加载扩展允许重写抽象方法使用 Argon2 算法生成密码散列新增 ext/PDO (PDO 扩展)字符串扩展类型PHP7.3特性取数组第一个/最后一个键PHP7.4特性数组延展操作符 (...$a)箭头函数 (=>)空合并运算赋值PHP8.0 特性从php7.4就跳到php8版本了8.0 是 PHP 语言的一个主版本更新。 它包含了很多新功能与优化项,命名参数、联合类型、注解、构造器属性提升、match 表达式、nullsafe 运算符、JIT,改进了类型系统、错误处理、语法一致性。PHP8.1特性PHP 8.1 是 PHP 语言的一个主版本更新。它包含了许多新功能枚举、只读属性、First-class 可调用语法、纤程、交集类型和性能改进等。
2022年04月17日
1,403 阅读
0 评论
0 点赞
2022-02-16
【转】代码的简洁之道
简介原文作者:Summer转自链接:https://learnku.com/laravel/t/62638版权声明:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请保留以上作者信息和原文链接。我最近遇到了 这条 Twitter,其中 @samuelstancl 列出了在 Laravel 中编写更干净代码的技巧, 以及一些通用的 Laravel 编码建议。 这些是培养对什么是好的代码和什么是坏的代码的感觉的一个很好的起点 - 所以我在下面整理了它们(带有代码示例),没有特定的顺序。细节决定成败干净的代码是微观层面不断做出正确决策的结果。使用表查找不要编写重复的 else if 语句,而是使用数组根据您拥有的键查找所需值。 代码将更清晰且更具可读性,如果出现问题,您将看到可以理解的异常。 没有半途而废的边缘情况。不好的// 不好的 if ($order->product->option->type === 'pdf') { $type = 'book'; } else if ($order->product->option->type === 'epub') { $type = 'book'; } else if ($order->product->option->type === 'license') { $type = 'license'; } else if ($order->product->option->type === 'artwork') { $type = 'creative'; } else if $order->product->option->type === 'song') { $type = 'creative'; } else if ($order->product->option->type === 'physical') { $type = 'physical'; } if ($type === 'book') { $downloadable = true; } else if ($type === 'license') { $downloadable = true; } else if $type === 'creative') { $downloadable = true; } else if ($type === 'physical') { $downloadable = false; }正确的// 正确的 $type = [ 'pdf' => 'book', 'epub' => 'book', 'license' => 'license', 'artwork' => 'creative', 'song' => 'creative', 'physical' => 'physical', ][$order->product->option->type]; $downloadable = [ 'book' => true, 'license' => true, 'creative' => true, 'physical' => false, ][$type];尽早返回通过尽早返回值来避免不必要的嵌套。过多的嵌套和 else 语句往往会使代码难以理解。槽糕写法// 糟糕的示例 if ($notificationSent) { $notify = false; } else if ($isActive) { if ($total > 100) { $notify = true; } else { $notify = false; } else { if ($canceled) { $notify = true; } else { $notify = false; } } } return $notify;推荐// 推荐的示例 if ($notificationSent) { return false; } if ($isActive && $total > 100) { return true; } if (! $isActive && $canceled) { return true; } return false;正确分割线不要在随机的地方分割线,但也不要让它们太长。 使用 [ 打开数组并缩进值往往效果很好。 与长函数参数值相同。 其他拆分行的好地方是链式调用和闭包。// 糟糕的示例 // 没有分行 return $this->request->session()->get($this->config->get('analytics.campaign_session_key')); // 无意义分行 return $this->request ->session()->get($this->config->get('analytics.campaign_session_key'));推荐// 推荐的示例 return $this->request->session()->get( $this->config->get('analytics.campaign_session_key') ); // 闭包 new EventCollection($this->events->map(function (Event $event) { return new Entries\Event($event->code, $event->pivot->data); })); // 数组 $this->validate($request, [ 'code' => 'string|required', 'name' => 'string|required', ]);不要创建没用的变量可以直接传值,就不要创建没用的变量。// 坏的 public function create() { $data = [ 'resource' => 'campaign', 'generatedCode' => Str::random(8), ]; return $this->inertia('Resource/Create', $data); }推荐// 好的 public function create() { return $this->inertia('Resource/Create', [ 'resource' => 'campaign', 'generatedCode' => Str::random(8), ]); }能提高可读性的时候再创建变量和上一条相反,有时候一个值来自一整套复杂的计算,因此创建一个变量,可以提高可读性,甚至连注释都省了。记住,上下文很重要,并且你编写代码的最终目标是让代码更具有可读性。// 坏的 Visit::create([ 'url' => $visit->url, 'referer' => $visit->referer, 'user_id' => $visit->userId, 'ip' => $visit->ip, 'timestamp' => $visit->timestamp, ])->conversion_goals()->attach($conversionData);推荐// 好的 $visit = Visit::create([ 'url' => $visit->url, 'referer' => $visit->referer, 'user_id' => $visit->userId, 'ip' => $visit->ip, 'timestamp' => $visit->timestamp, ]); $visit->conversion_goals()->attach($conversionData);根据业务逻辑来创建模型的方法控制器应该尽量保持简单。 比如以 “为订单创建发票” 这样的方式调用方法。调用方法不需要关心你的数据库表结构的细节,这些由模型自己内部实现。// 糟糕的方式 // 为订单创建发票 DB::transaction(function () use ($order) { Sinvoice = $order->invoice()->create(); $order—>pushStatus(new AwaitingShipping); return $invoice; });// 优雅的方式 $order->createInvoice();创建动作类让我们来继续刚才的例子。有时,可以为某个动作单独创建一个类,这样会使代码更加整洁。模型封装的业务逻辑可以基于动作类,但是记得动作类不可太大。// 糟糕的方式 public function createInvoice(): Invoice { if ($this->invoice()->exists()) { throw new OrderAlreadyHasAnInvoice('Order already has an invoice.'); } return DB::transaction(function () use ($order) { $invoice = $order->invoice()->create(); $order->pushStatus(new AwaitingShipping); return $invoice; }); }推荐// 优雅的方式 // 订单模型 public function createInvoice(): Invoice { if ($this->invoice()->exists()) { throw new OrderAlreadyHasAnInvoice('Order already has an invoice.'); } return app(CreateInvoiceForOrder::class)($this); } // 订单创建发票动作类 class CreatelnvoiceForOrder { public function _invoke(Order $order): Invoice { return DB::transaction(function () use ($order) { $invoice = $order->invoice()->create(); $order->pushStatus(new AwaitingShipping); return $invoice; }); } }考虑表单请求考虑使用表单请求,它们是隐藏复杂验证逻辑的好地方,但要注意这一点 — 隐藏的东西。当您的验证逻辑很简单时,在控制器中执行它并没有错,将其移至表单请求使其变得不那么明确。/** * 获取适用于请求的验证规则. * * @返回数组 */ public function rules() { return [ 'title' => 'required|unique:posts|max:255', 'body' => 'required', ]; }使用事件考虑将一些逻辑从控制器写到事件。例如,在创建模型时,好处是创建这些模型在任何地方 (控制器,任务,…) 并且控制器不必担心 DB 模式的细节。// 糟糕的示例 // 只在这个地方有效并关注它 // 模型应该关心的细节. if (! isset($data['name'])) { $data['name'] = $data['code']; } $conversion = Conversion::create($data);// 推荐的示例 $conversion = Conversion::create($data); // 模型 class ConversionGoal extends Model { public static function booted() { static::creating(function (self $model) { $model->name ??= $model->code; }); } }拆分方法如果某些方法太长或是太复杂,很难理解究竟做了什么,可以尝试将复杂的逻辑拆分成多个方法。public function handle(Request $request, Closure $next) { // 我们将三段逻辑分别提取成单独的方法 $this->trackVisitor(); $this->trackCampaign(); $this->trackTrafficSource($request); $response = $next($request); $this->analytics->log($request); return $response; }创建助手函数如果你多次重复一段代码,考虑一下将它们提取为助手函数是不是可以让代码更简洁。// app/helpers.php 文件,在 composer.json 中自动加载 function money(int $amount, string $currency = null): Money { return new Money($amount, $currency ?? config('shop.base_currency')); } function html2text($html = ''): string { return str_replace(' ', ' ', strip_tags($html)); }避免使用助手类有时候人们会使用类来归类助手函数(注意),可要小心了,这可能会让代码变得更混乱。常见的做法是定义一个只包含一个作为助手函数使用的静态方法的类。更好的做法是将这些方法放入具有具体逻辑的类中,或者是只将它们当做是全局函数。// 坏的 class Helper { public function convertCurrency(Money $money, string $currency): self { $currencyConfig = config("shop.currencies.$currency"); $decimalDiff = ... return new static( (int) round($money->baseValue() * $currencyConfig[value] * 10**$decimalDiff, 0), $currency ); } } // 使用 use App\Helper; Helper::convertCurrency($total, 'EUR');// 好的 class Money { // 其他的 money/currency 逻辑 public function convertTo(string $currency): self { $currencyConfig = config("shop.currencies.$currency"); $decimalDiff = ... return new static( (int) round($this->baseValue() * $currencyConfig[value * 10**$decimalDiff, 0), $currency ); } } // 使用 $EURtotal = $total->convertTo('EUR');拿出一个周末来学习 OO了解静态(static)/ 实例(instance)方法和变量,还有私有的(private)/ 保护的(protected)/ 公共的(public)之间的可见性的区别。还要了解 Laravel 如何使用魔法方法。当你是初学者的时候可能不会很常用,但是随着你的编码水平增长,这些是至关重要的。不要在类中只写过程代码这将前面的推文与此处的其他提示联系起来。OOP 的存在就是为了让你的代码更加具有可读性,请使用 OOP。不要再在控制器中写好几百行的过程代码了!!!。阅读 SRP 之类的内容,并进行合理的扩展避免使用那种处理很多和当前类不相关逻辑的类,但是也不要为每件事都创建一个类。你是为了写干净的代码,而不是想在每件事上都做分离。避免函数中参数过多当您看到具有大量参数的函数时,它可能意味着:该函数包含太多职责,应该分离。职责没问题,但你应该学会重构他的长签名.以下是修复第二种情况的两种策略使用数据传输对象 (DTO)与其以特定顺序传递大量参数,不如考虑创建一个具有属性的对象来存储这些数据。 如果您发现某些行为可以移入此对象,则可以加分。// 糟糕的示例 public function log($url, $route_name, $route_data, $campaign_code, $traffic_source, $referer, $user_id, $visitor_id, $ip, $timestamp) { // ... }// 推荐的示例 public function log(Visit $visit) { // ... } class Visit { public string $url; public ?string $routeName; public array $routeData; public ?string $campaign; public array $trafficSource[]; public ?string $referer; public ?string $userId; public string $visitorId; public ?string $ip; public Carbon $timestamp; // ... }创建流式对象你可以使用流式 API 来创建对象。使用单独的方法调用来逐渐添加数据,并且只要构造函数中的绝对最小值。正是因为每个方法都返回 $this ,你可以在任意一次调用后让整个流程停下来。Visit::make($url, $routeName, $routeData) ->withCampaign($campaign) ->withTrafficSource($trafficSource) ->withReferer($referer) // ... 等等使用自定义集合创建自定义集合可以更好地写出更富有表现力的语法。参考这个订单合计的示例:// 坏的 $total = $order->products->sum(function (OrderProduct $product) { return $product->price * $product->quantity * (1 + $product->vat_rate); });// 好的 $order->products->total(); class OrderProductCollection extends Collection { public function total() { $this->sum(function (OrderProduct $product) { return $product->price * $product->quantity * (1 + $product->vat_rate); }); } }不要使用缩写不要觉得很长的变量名 / 方法名就是不对的,才不是这样,它们很有表现力。使用一个长的方法名比短的更好,配合查阅文档能更完整地了解它的功能。变量也是如此。不要使用无意义的几个字母的缩写。// 坏的 $ord = Order::create($data); // ... $ord->notify();// 好的 $order = Order::create($data); // ... $order->sendCreatedNotification();尝试在控制器中只使用 CURD 动作如果可以的话,只使用控制器中的 7 个 CURD 动作,通常来说会更少。不要在控制器中创建 20 多个方法,更短的控制器更好一些。使用更具有表现力的方法名称考虑「这个对象可以完成什么事情」,而不是「这个对象能做什么」。也会有例外,比如操作类。这是个很好的经验。// 坏的 $gardener->water($plant); $orderManager->lock($order);// 好的 $plant->water(); $order->lock();创建单次使用的 trait将方法添加到它所属的类中,比为每件事都创建操作类简洁得多,但是这会让类变得很大。尝试使用特征 traits,它主要是为了代码复用,但是单次使用的 trait 并没有错。class Order extends Model { use HasStatuses; // ... } trait HasStatuses { public static function bootHasStatuses() { ... } public static $statusMap = [ ... ]; public static $paymentStatusMap = [ ... ]; public static function getStatusId($status) { ... } public static function getPaymentStatusId($status): string { ... } public function statuses() { ... } public function payment_statuses() { ... } public function getStatusAttribute(): OrderStatusModel { ... } public function getPaymentStatusAttribute(): OrderPaymentStatus { ... } public function pushStatus($status, string $message = null, bool $notification = null) { ... } public function pushPaymentStatus($status, string $note = null) { ... } public function status(): OrderStatus { ... } public function paymentStatus(): PaymentStatus { ... } }创建一次性引入类似于一次性 traits. 当您有一个很长的模板并且希望使其更易于管理时,这种策略非常有用。布局中的 @include-ing 页眉和页脚或页面视图中的复杂表单等都没有问题。导入命名空间而不是使用别名有时您可能有多个同名的类。 与其使用别名导入它们,不如导入命名空间。// 糟糕的示例 use App\Types\Entries\Visit as VisitEntry; use App\Storage\Database\Models\Visit as VisitModel; class DatabaseStorage { public function log(VisitEntry $visit) { $visitModel = VisitModel::create([ // ... ]); } }// 推荐的示例 use App\Types\Entries; use App\Storage\Database\Models; class DatabaseStorage { public function log(Entries\Visit $visit) { $visitModel = Models\Visit::create([ // ... ]); } }为 where() 创建查询方法使用更具有表现力的名字创建查询方法,而不是编写完整的 where()。这可以让你的代码(例如控制器)尽可能更少地与数据库结构产生耦合,并且可以让代码更清晰。// 不好的 Order::whereHas('status', function ($status) { return true$status->where('canceled', true); })->get();// 好的 Order::whereCanceled()->get(); class Order extends Model { public function scopeWhereCanceled(Builder $query) { return $query>whereHas('status', function ($status) { return $status->where('canceled', true); }); } }不要使用模型方法来检索数据如果你想要从模型中获取数据,可以创建一个访问器。保留以某种方式改变模型的方法。// 坏的 $user->gravatarUrl(); class User extends Authenticable { // ... public function gravatarUrl() { return "https://www.gravatar.com/avatar/" . md5(strtolower(trim($this->email))); } }// 好的 Suser->gravatar_url; class User extends Authenticable { // ... public function getGravatarUrlAttribute() { return "https://www.gravatar.com/avatar/" . md5(strtolower(trim($this->email))); } }使用自定义配置文件你可以在配置文件中存储类似「每页几条数据」这样的内容。不要直接将它们放在 app 配置文件中。创建你自己的配置文件。例如,在一个电商项目中,你可以使用 config/shop.php。// config/shop.php return [ 'vat rates' => [ 0.21, 0.15, 0.10, 0.0, ], 'fee_vat_rate' => 0.21, 'image_sizes' => [ 'base' => 500, // detail 't1' => 250, // index 't2' => 50, // search ], ];不要使用控制器命名空间使用可调用的数组语法 [PostController::class, 'index'] ,而不是直接写控制器和方法名 PostController@index。这样写的话你可以点击 PostController 来跳转到类的定义。// 坏的 Route::get('/posts', 'PostController@index');// 好的 Route::get('/posts', [PostController::class, 'index']);考虑使用单动作控制器如果你有复杂的路由操作,考虑将它放在单独的控制器中。对于 OrderController::create,你可以创建 CreateOrderController。另一个解决方法是将该逻辑转移到一个动作类 —— 在你的实际情况中选择最好用的方法。// 我们使用上面提到的类语法 Route::post('/orders/', CreateOrderController::class); class CreateOrderController { public function _invoke(Request $request) { // ... } }友好型 IDE安装扩展,编写注释,使用类型提示。 您的 IDE 将帮助您让您的代码正常工作,这让您可以将更多的精力花在编写可读的代码上。$products = Product::with('options')->cursor(); foreach ($products as $product) { /** @var Product $product */ if ($product->options->isEmpty()) { // ... } } /////////////////////////// foreach (Order::whereDoesntHave('invoice')->whereIn('id', $orders->pluck('id'))->get() as $order) { /** @var Order $order */ $order->createInvoice(); // ... } /////////////////////////// $productImage ->help('Max 2 MB') ->store(function (NovaRequest $request, ProductModel $product) { /** @var UploadedFile $image */ $image = $request->image; // ... });使用短运算符PHP 有很多很棒的操作符可以替代丑陋的 if 检查。 记住它们。// 糟糕的 // truthy test if (! $foo) { $foo = 'bar'; } // null test if (is_null($foo)) { $foo = 'bar'; } // isset test if (! isset($foo)) { $foo = 'bar'; }// 优雅的 // truthy test $foo = $foo ?: 'bar'; // null test $foo = $foo ?? 'bar'; // PHP 7.4 $foo ??= 'bar'; // isset test $foo = $foo ?? 'bar'; // PHP 7.4 $foo ??= 'bar';决定您是否喜欢运算符周围的空格在上面你可以看到我在 ! 和我要否定的值之间使用了空格。 我喜欢这个,因为它清楚地表明该值被否定了。 我在点周围做同样的事情。 可以按照您的喜好来清理您的代码。助手函数而不是 Facades考虑使用助手函数而不是 Facades 。 因为他们可以使得代码变得很整洁。 这在很大程度上取决于个人喜好,但调用全局函数而不是导入类并静态调用方法对我来说感觉更好。 session('key') 语法的加分项。// 糟糕的示例 Cache::get('foo');// 推荐的示例 cache()->get('foo'); // Better cache('foo');为业务逻辑创建自定义 Blade 指令你可以通过创建自定义指令来让你的 Blade 模板更具有表现力。举个例子,你可以使用 @admin 来检查用户是否是管理员,而不是使用具体的逻辑来判断。// 不好的写法 @if(auth()->user()->hasRole('admin')) // ... @else // ... @endif// 好的写法 @admin // ... @else // ... @endadmin避免在 Blade 中查询数据库可能有的时候你想要在 Blade 中查询数据库。有些情况下这是可以的,例如布局文件。但是如果是在视图文件中,则需要在控制器中向视图传入查询好的数据。// 不好的写法 @foreach(Product::where('enabled', false)->get() as $product) // ... @endforeach// 好的写法 // 控制器 return view('foo', [ 'disabledProducts' => Product::where('enabled', false)->get(), ]); // 视图 @foreach($disabledProducts as $product) // ... @endforeach使用精确的比较运算符始终使用严格比较(=== 和 !==)。 如果需要,在比较之前将事物转换为正确的类型。 比奇怪的 == 结果要好。 还要考虑在您的代码中启用严格类型。 这将防止将错误数据类型的变量传递给函数。// 糟糕的示例 $foo == 'bar';// 推荐的示例 $foo === 'bar'; // Better declare(strict_types=1);仅当他们澄清事情时才使用文档块很多人会不同意这一点,因为他们这样做了。 但这没有任何意义。 当它们不提供任何额外信息时,使用 文档是没有意义的。 如果类型提示足够了,就不要添加文档块,那样只是多余的。// 糟糕的示例 // 全部没有类型 function add_5($foo) { return $foo + 5; } // @param 注释精确地添加了 0% 值和 100% 噪声。 /** *给一个数加 5。 * * @param int $foo * @return int */ function add_5(int $foo): int { return $foo + 5; }// 推荐的示例 // 没有文档块,一切都清楚 function add_5(int $foo) { return $foo + 5; } //类型提示说得尽可能多,注释说得更多。 /** * 把单词变成句子。 * * @param string[] $words * @返回字符串 */ function sentenceFromWords(array $words): string { return implode(' ', $words) . '.'; } // 个人最爱。 只使用能带来价值的注解。 不要仅仅因为它太常见就使用 description 或 @return。 /** @param string[] $words */ function sentenceFromWords(array $words): string { return implode(' ', $words) . '.'; }验证规则有单一的真实来源如果你在多个地方验证某个资源的属性,你肯定希望将这些验证规则集中起来,这样你就不会在一个地方更改它们而忘记其他地方。 我经常发现自己在模型的方法中保留了验证规则。 这让我可以在任何需要的地方重用它们 —— 包括在控制器或表单请求中。class Reply extends Model { public static function getValidationRules(): array { return [ 'thread_id' => ['required', 'integer'], 'user_id' => ['required', 'integer'], 'body' => ['required', 'string', new SpamRule()], ]; } }可以使用集合来优化代码不要仅仅因为 Laravel 提供它们就将所有数组转换为集合,而是当您可以使用集合语法来优化代码时将数组转换为集合。$collection = collect([ ['name' => 'Regena', 'age' => null], ['name' => 'Linda', 'age' => 14], ['name' => 'Diego', 'age' => 23], ['name' => 'Linda', 'age' => 84], ]); $collection->firstWhere('age', '>=', 18);在对你有利的时候编写函数式代码函数式代码不仅能使代码整洁,还能降低代码的易读性。 将常见循环重构为函数调用,但不要为了避免编写循环而编写愚蠢复杂的 reduce ()。 两者都有一个用例。// 糟糕的示例 return array_unique(array_reduce($keywords, function ($result, $keyword) { return array_merge($result, array_reduce($this->variantGenerators, function ($result2, $generator) use ($keyword) { return array_merge($result2, array_map(function ($variant) { return strtolower($variant); }, $generator::getVariants($keyword))); }, [])); }, []));// 推荐的示例 return $this->items()->reduce(function (Money $sum, OrderItem $item) { return $sum->addMoney($item->subtotal()); }, money(0, $this->currency));注释通常表明代码设计不佳在撰写评论之前,问问自己是否可以重命名某些内容或创建变量以提高可读性。 如果这是不可能的,请以您和您的同事在 6 个月后都能理解的方式撰写评论。上下文问题上面我说将业务逻辑转移到逻辑类 / 服务类是好的。 但上下文很重要, 这是来自流行的 “Laravel 最佳实践” 存储库的代码设计建议。 绝对没有理由将 3 行检查放入类中。 这只是过度设计。// 糟糕的示例 public function store(Request $request) { $this->articleService->handleUploadedImage($request->file('image')); } class ArticleService { public function handleUploadedImage($image) { if (!is_null($image)) { $image->move(public_path('images') . 'temp'); } } }// 推荐的示例 public function store(Request $request) { if ($request->hasFile('image')) { $request->file('image')->move(public_path('images') . 'temp'); } // ... }只使用对你有帮助的东西,忽略其他一切您的目标是编写更具可读性的代码。您的目标不是按照某人在互联网上所说的那样去做。这些技巧只是有助于写出优雅的代码。 牢记你的最终目标并问自己「这样更好吗?」
2022年02月16日
227 阅读
1 评论
0 点赞
2021-04-22
PhpSpreadsheet实现导入&导出功能
前文导入excel的文本内容如下代码演示composer安装PhpSpreadsheet (这是新的Excel类库),不用旧的PHPExcel的类库,旧的已被官网弃用不维护了!!前端代码<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="./index5.php" method="post" enctype="multipart/form-data"> <input type="file" name="fileUpload" /> <input type="submit" value="上传文件" /> </form> </body> </html>后端代码 require_once 'vendor/autoload.php'; $filePath = $_FILES['fileUpload']['tmp_name']; $reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader('Xlsx'); $reader->setReadDataOnly(TRUE); $spreadsheet = $reader->load($filePath); //载入excel表格 $worksheet = $spreadsheet->getActiveSheet(); $highestRow = $worksheet->getHighestRow(); // 总行数 $highestColumn = $worksheet->getHighestColumn(); // 总列数 $highestColumnIndex = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::columnIndexFromString($highestColumn); // e.g. 5 $lines = $highestRow - 1; if ($lines <= 0) { exit('Excel表格中没有数据'); } $import_data = []; for ($i = 2; $i <= $highestRow; $i++) { $import_data[$i]['id'] = $spreadsheet->getActiveSheet()->getCell("A" . $i)->getValue(); $import_data[$i]['nick_name'] = $spreadsheet->getActiveSheet()->getCell("B" . $i)->getValue(); $import_data[$i]['number'] = $spreadsheet->getActiveSheet()->getCell("C" . $i)->getValue(); $import_data[$i]['vip_number'] = $spreadsheet->getActiveSheet()->getCell("D" . $i)->getValue(); $import_data[$i]['card'] = $spreadsheet->getActiveSheet()->getCell("E" . $i)->getValue(); } $import_data = array_values($import_data);//重置索引 echo "<pre>"; print_r($import_data);exit; exit; 第二种方式不用$spreadsheet读取的文件的变量句柄,用 $worksheet获取所有的表格行数,先获取某一个sheet。 require_once 'vendor/autoload.php'; $filePath = $_FILES['fileUpload']['tmp_name']; $reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader('Xlsx'); $reader->setReadDataOnly(TRUE); $spreadsheet = $reader->load($filePath); //载入excel表格 $worksheet = $spreadsheet->getActiveSheet(); $highestRow = $worksheet->getHighestRow(); // 总行数 $highestColumn = $worksheet->getHighestColumn(); // 总列数 $highestColumnIndex = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::columnIndexFromString($highestColumn); // e.g. 5 $lines = $highestRow - 1; if ($lines <= 0) { exit('Excel表格中没有数据'); } for ($row = 2; $row <= $highestRow; ++$row) { $temp = array( 'id' => $worksheet->getCellByColumnAndRow('1', $row)->getValue(), 'nick_name' => $worksheet->getCellByColumnAndRow('2', $row)->getValue(), 'number' => $worksheet->getCellByColumnAndRow('3', $row)->getValue(), 'vip_number' => $worksheet->getCellByColumnAndRow('4', $row)->getValue(), 'card' => $worksheet->getCellByColumnAndRow('5', $row)->getValue(), 'other' => $worksheet->getCellByColumnAndRow('6', $row)->getValue(), 'addr' => $worksheet->getCellByColumnAndRow('7', $row)->getValue(), ); $list[] = $temp; } echo "<pre>"; print_r($list);exit;这样就可以根据数据入数据库了导出 require_once 'vendor/autoload.php'; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; use PhpOffice\PhpSpreadsheet\Cell\DataValidation; use PhpOffice\PhpSpreadsheet\IOFactory; function exportExcel(){ //定义一个excel的header表头 $header = ['A1' => '序号', 'B1' => '姓名', 'C1' => '证件号', 'D1' => '张数', 'E1' => '证件类型', 'F1' => '省', 'G1' => '市', 'H1' => '区/镇', 'I1' => '类别', 'J1' => '设计人', 'K1' => '完成时间', 'L1' => '备注']; $list = [ ['id'=>1,'name'=>'黎明强','card'=>'13800','number'=>10], ['id'=>2,'name'=>'黎明','card'=>'13811','number'=>100], ['id'=>3,'name'=>'黎明强森','card'=>'13822','number'=>200], ['id'=>4,'name'=>'黎明强2','card'=>'13833','number'=>300], ['id'=>5,'name'=>'黎明强3','card'=>'13844','number'=>400], ]; $spreadsheet = new Spreadsheet(); $sheetMain = $spreadsheet -> getsheet(0);//主sheet $sheetMain -> setTitle('人员信息');//设置sheet的名称 $sheetMain -> getPageSetup() -> setHorizontalCentered(true); $sheetMain -> getPageSetup() -> setVerticalCentered(false); foreach ($header as $key => $value) { $sheetMain -> setCellValue($key, $value); } $row = 2; //从第二行开始 foreach ($list as $item) { $column = 1; foreach ($item as $value) { $sheetMain->setCellValueByColumnAndRow($column, $row, $value); $column++; } $row++; } //定义文件名称,需要带有定义的后缀名 $filename = 'test.xlsx'; ob_end_clean(); //清除缓冲区,避免乱码 //将输出重定向到客户端的web浏览器 header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); header('Content-Disposition: attachment;filename="' . $filename . '"'); header('Cache-Control: max-age=0'); //如果浏览器为IE9 header('Cache-Control: max-age=1'); //如果通过SSL向IE提供服务 header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); header('Cache-Control: cache, must-revalidate');//HTTP/1.1 header('Pragma: public');//HTTP/1.0 $writer = IOFactory ::createWriter($spreadsheet, 'Xlsx'); //指定格式 $writer -> save('php://output'); exit; }运行exportExcel();
2021年04月22日
1,176 阅读
2 评论
0 点赞
2020-12-24
php替换新源安装php7
安装PHP替换新的yum源yum源默认的版本太低了,手动安装有一些麻烦,想采用Yum更新安装的可以使用下面的方案1.检查当前安装的PHP包yum list installed | grep php如果有安装的PHP包,先删除他们yum remove php.x86_64 php-cli.x86_64 php-common.x86_64 php-gd.x86_64 php-ldap.x86_64 php-mbstring.x86_64 php-mcrypt.x86_64 php-mysql.x86_64 php-pdo.x86_642. 更换rpm源Centos 5.X: rpm -Uvh http://mirror.webtatic.com/yum/el5/latest.rpm CentOs 6.x: rpm -Uvh http://mirror.webtatic.com/yum/el6/latest.rpm CentOs 7.X: rpm -Uvh https://mirror.webtatic.com/yum/el7/epel-release.rpm rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm替换新源后,yum search会多出很多选择,比如 php56w 、php70w、php73w、php56w-fpm#查看 (查看源) yum search php 如果想删除上面安装的包,重新安装rpm -qa | grep webstatic rpm -e 上面搜索到的包即可3.安装安装php包含其他模块需要的依赖//php5.5 yum install php55w.x86_64 php55w-cli.x86_64 php55w-common.x86_64 php55w-gd.x86_64 php55w-ldap.x86_64 php55w-mbstring.x86_64 php55w-mcrypt.x86_64 php55w-mysql.x86_64 php55w-pdo.x86_64 //php5.6 yum install php56w.x86_64 php56w-cli.x86_64 php56w-common.x86_64 php56w-gd.x86_64 php56w-ldap.x86_64 php56w-mbstring.x86_64 php56w-mcrypt.x86_64 php56w-mysql.x86_64 php56w-pdo.x86_64 //php7.0 yum install php70w.x86_64 php70w-cli.x86_64 php70w-common.x86_64 php70w-gd.x86_64 php70w-ldap.x86_64 php70w-mbstring.x86_64 php70w-mcrypt.x86_64 php70w-mysql.x86_64 php70w-pdo.x86_64根据你需要的版本选择4.安装php-fpmyum install php55w-fpm yum install php56w-fpm yum install php70w-fpm 设置开机自启systemctl enable php70w-fpm【开机自启动】本次更新升级PHP版本即可完成!
2020年12月24日
950 阅读
0 评论
0 点赞
2020-11-10
PHP设置脚本最大执行时间的三种方法
php.ini 中缺省的最长执行时间是 30 秒,这是由 php.ini 中的 max_execution_time 变量指定,如果脚本需要跑很长时间,例如要大量发送电子邮件,或者分析统计大量数据,服务器会在 30 秒后强行中止正在执行的程序,这种情况就要更改php脚本最大执行时间。PHP设置脚本最大执行时间的三种方法在php.ini里面设置max_execution_time = 120;通过PHP的ini_set函数设置ini_set("max_execution_time", "120"); 设置120秒的意思通过set_time_limit 函数设置set_time_limit(120);以上几个数字设置为0则无限制,脚本会一直执行下去,直到执行结束。所以,需要长时间执行的脚本,一般在php代码开头处添加如下代码就可以了 set_time_limit(0);注意:方法一主要适用于网站已经做好了,后期维护人员对代码结构不熟悉,方法二和三适用于写代码时候,不过不推荐使用方法二,因为要注意ini_set函数是否会被禁用
2020年11月10日
1,623 阅读
0 评论
0 点赞
2020-11-08
PHP生成随机字符串
当我们需要生成一个随机名字,临时密码等字符串时可以用到下面的函数:代码如下function generateRandomString($length = 10) { $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; $randomString = ''; for ($i = 0; $i < $length; $i++) { $randomString .= $characters[rand(0, strlen($characters) - 1)]; } return $randomString; }使用方法echo generateRandomString(20);生成随机字符串/** * 随机生成字符串 * @param int $length * @return null|string */ private static function getRandChar($length = 8){ $str = null; $strPol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz"; $max = strlen($strPol)-1; for($i=0;$i<$length;$i++){ $str.=$strPol[rand(0,$max)]; //rand($min,$max)生成介于min和max两个数之间的一个随机整数 } return $str; }
2020年11月08日
1,213 阅读
1 评论
0 点赞
2020-11-07
令人困惑的strtotime
经常会有人被strtotime结合-1 month, +1 month, next month的时候搞得很困惑, 然后就会觉得这个函数有点不那么靠谱, 动不动就出问题. 用的时候就会很慌…这不, 刚刚就有人在微博上又问我:鸟哥,今天是2018-07-31 执行代码:date("Y-m-d",strtotime("-1 month")) 怎么输出是2018-07-01?好的吧, 虽然这个问题看起来很迷惑, 但从内部逻辑上来说呢, 其实是”对”的, 你先别着急哈, 让我慢慢讲:我们来模拟下date内部的对于这种事情的处理逻辑:先做-1 month, 那么当前是07-31, 减去一以后就是06-31.再做日期规范化, 因为6月没有31号, 所以就好像2点60等于3点一样, 6月31就等于了7月1是不是逻辑很”清晰”呢? 我们也可以手动验证第二个步骤, 比如:var_dump(date("Y-m-d", strtotime("2017-06-31"))); //输出2017-07-01也就是说, 只要涉及到大小月的最后一天, 都可能会有这个迷惑, 我们也可以很轻松的验证类似的其他月份, 印证这个结论:var_dump(date("Y-m-d", strtotime("-1 month", strtotime("2017-03-31")))); //输出2017-03-03 var_dump(date("Y-m-d", strtotime("+1 month", strtotime("2017-08-31")))); //输出2017-10-01 var_dump(date("Y-m-d", strtotime("next month", strtotime("2017-01-31")))); //输出2017-03-03 var_dump(date("Y-m-d", strtotime("last month", strtotime("2017-03-31")))); //输出2017-03-03那怎么办呢?从PHP5.3开始呢, date新增了一系列修正短语, 来明确这个问题, 那就是”first day of” 和 “last day of”, 也就是你可以限定好不要让date自动”规范化”:var_dump(date("Y-m-d", strtotime("last day of -1 month", strtotime("2017-03-31")))); //输出2017-02-28 var_dump(date("Y-m-d", strtotime("first day of +1 month", strtotime("2017-08-31")))); ////输出2017-09-01 var_dump(date("Y-m-d", strtotime("first day of next month", strtotime("2017-01-31")))); ////输出2017-02-01 var_dump(date("Y-m-d", strtotime("last day of last month", strtotime("2017-03-31")))); ////输出2017-02-28那如果是5.3之前的版本(还有人用么?), 你可以使用mktime之类的, 把所有的日子忽略掉, 比如都限定为每月1号就可以了, 只不过就不如直接用first day来的更加优雅.现在, 搞清楚了内部原理, 是不是就不慌了?
2020年11月07日
889 阅读
2 评论
0 点赞
1
2