PHP核心技术与最佳实践(二)

五、PHP与数据库基础

A.什么是PDO

1.连接mysql的三种方式:

①MySQL系列函数

②MySQLi系列函数

③PDO:为PHP定义了一个访问数据库的轻量、持久的接口,实现PDO接口的每一种数据库驱动都能以正则扩展的形式把各自的特色表现出来。

2.PDO包含三个重要的类:PDO、PDOStatement、PDOException

3.事务,使用beginTransaction()、commit()、rollBack()

4.效率:60多张表2G左右数据库进行CRUD效率比mysql直连慢5%-15%,对效率要求高的应使用直连。负载在开启长连接后高于mysql直连且比较稳定

B.数据库应用优化

1.基本语句优化10个原则

①尽量避免在列上进行运算,这样会导致索引失效

②使用JOIN时,应该用小结果集驱动大结果集。同时把复杂的JOIN查询拆分成多个Query。因为JOIN多个表时,可能导致更多的锁定和堵塞。

③注意LIKE模糊查询的使用,避免%%

④仅列出需要查询的字段 ,这对速度不会有明显的影响,主要考虑节省内存

⑤使用批量插入语句节省交互

⑥limit的基数比较大时使用between

⑦不要使用rand函数获取多条随机记录

⑧避免使用NULL

⑨不要使用count(id),而应该是count(*)

⑩不要做无谓的排序操作,而应尽可能在索引中完成排序

2.索引与性能分析

EXPLAIN属性说明:

  • id:查询的序列号
  • select_type:查询的类型,主要包括普通查询、联合查询和子查询
  • table:所访问的数据库中表的名称
  • type:联合查询使用的类型:由好到坏依次为system(系统表)、const(常量)、eq_ref(最多一条匹配结果)、ref(被驱动表索引)、fulltext(全文索引检索)、ref_or_null(带空值的索引查询)、index_merge(合并索引结果集)、unique_subquery(子查询中返回的字段是唯一组合或索引)、index_subquery(子查询返回的是索引,但非主键)、range(索引范围扫描)、index(全索引扫描)、ALL(全表扫描)
  • possible_keys:指出MySQL能使用哪个索引在该表中找到该行。如果没使用则为空
  • key:显示MySQL实际决定使用的键
  • key_len:显示MySQL决定使用的键长度。可以反映出一个多主键里MySQL实际使用了哪部分。
  • ref:显示哪个字段或常数与key一起被使用
  • rows:表示MySQL要遍历多少数据才能找到所需的结果集,在InnoDB上是不准确的
  • Extra:如果是only index,表明信息只能用索引树中的信息检索;where used表明使用了where限制,但是索引不够;impossible where,表明通过收集到的统计信息判断出不可能存在结果;using filesort,表示包含orderby且无法使用索引进行派讯操作,不得不使用相应的派讯算法实现;using temporary,表明使用临时表,常见于orderby和group by;select tables optimized way,使用聚合函数,并且MySQL进行了快速定位,通常是MAX、MIN、COUNT等

3.索引至少达到range级,最好能达到ref级

4.索引建立和使用的基本原则:

①合理设计和合理使用索引

②在关键字段的索引上,建与不建索引,查询速度相差近百倍

③差的索引和没有索引效果一样

④索引并非越多越好,因为维护索引需要成本

⑤每个表的索引应在5个以下,应合理利用部分索引和联合索引

⑥不在结果集中的结果单一的列上建索引

⑦建索引的字段结果集最好分页均匀,或者符合正太分布

5.选择存储引擎

①采用MyISAM:R/W>100:1且update相对较少;并发不高,不需要事务;表数据量小;硬件资源有限;

②采用InnoDB:R/W比较小,频繁更新大字段;表数据量超过1000万,并发高;安全性和可用性要求高;

③采用Memory:有足够的内存;对数据一致性要求不高;需要定期归档的数据;

6.MySQL瓶颈及应对措施

①提高服务器配置

②使用第三方引擎,Percona、MariaDB等

③迁移到其他数据库,Oracle等

④分区、分表

⑤使用NoSQL

⑥使用中间件做数据拆分和分布式数据,Cobar等

⑦使用数据库连接池技术

C.数据库设计

1.设计数据库时原则:

①核心业务使用范式

②弱一致性需求—反ACID

③空间换时间,冗余换效率

④避免不必要的冗余

D.MySQL的高级应用

1.序列表

2.视图:mysql中视图等价于依据查询语句,进行查询时只是将视图展开成其定义的语句。因此不能提升效率。

好处:实现了更细致的权限控制;把业务中常用的SQL语句用一个视图来表示更直观;性能优势在别的数据库中可体现。

3.存储过程和事件调度

4.SQL注入漏洞与防范

①如果是整型,使用intval()

②字符类型使用addslashes()

③转义及过滤一些特殊字符

④保护表结构等关键信息

⑤做好数据库备份

https://github.com/zhangyue0503/php/blob/master/phphexinjishuyuzuijiashijian/4.php

六、PHP模板引擎的原理与实践

A.模板引擎骨架

开发思路:

①模板引擎要做的事情就是把逻辑层和表现层的代码分离,这是一个大原则。

②作为一个工具类,应该满足一些基本要求,其中之一就是可配置

③确定模板引擎到底需要一些什么功能,需要哪些特性

https://github.com/zhangyue0503/php/blob/master/phphexinjishuyuzuijiashijian/5.php

https://github.com/zhangyue0503/php/blob/master/phphexinjishuyuzuijiashijian/Template.php

https://github.com/zhangyue0503/php/blob/master/phphexinjishuyuzuijiashijian/member.m

七、PHP扩展开发

A.PHP的生命周期

1.一个php实例,无论是从init脚本中调用的,还是从命令行启动的,都会依次经过Module init、Request init、Request shutdown、Module shutdown四个过程

2.最常见的四种启动php的方式:直接以CLI/CGI模式调用、多进程模块、多线程模块、Embedded(嵌入式,在自己的C程序中调用Zend Engine)

3.SAPI(Server abstraction API),服务器抽象化程序接口,提供一个接口,使PHP可以和其他应用进行交互,例如与Apache起交互

B.PHP内核中的变量

1.写时复制

两个指向同一内存块的变量,当其中一个变量的值发生变化,才会另外创建一个内存块去保存新的值。也是一种引用,不过会受变量值的改变而破坏。

C.Zend引擎

1.是脚本语言引擎(解析器+虚拟机),主要的工作就是解析、翻译和执行PHP脚本。

2.编译PHP脚本,输出Opcodes;解析执行Opcodes,输出结果。

D.PHP扩展包含

①包含头文件:php.h

②声明导出函数

③声明Zend函数块

④声明Zend模块

⑤实现get_module()函数

⑥实现导出函数

https://github.com/zhangyue0503/php/blob/master/phphexinjishuyuzuijiashijian/6.php

https://github.com/zhangyue0503/php/blob/master/phphexinjishuyuzuijiashijian/php_list

八、缓存详解

A.认识缓存

1.凡是位于速度相关较大的两种介质之间,用于协调两者数据传输速度差异的结构,均可称为Cache。

2.命中率指请求缓存次数和缓存返回正确结果次数的比例。

3.缓存更新策略:FIFO(First In First Out)最先进入缓存的数据在缓存空间不够的情况下会被首先清理出去;LFU(Less Frequently Used)最少使用的元素会被清理掉;LRU(Least Recently Used)最近最少使用的元素被清理。

4.缓存最大数据量:是在缓存中能处理元素的最大个数或所能使用的最大存储空间,mysql由query_cache_size参数决定

超过后四种处理方式:

①停止缓存服务

②拒绝写入

③根据缓存更新策略清除旧数据

④在方式3的基础上,将淘汰的数据备份,腾出新的空间

B.文件缓存

1.优点:容量大;稳定;固态硬盘提升速度;扩展容易;

C.Opcode缓存

1.Opcode(Operation Code,操作码)就是虚拟机把PHP代码编译成一种中间码的结果缓存起来(可以缓存到硬盘或者内存中)。下一次运行此页面时,只要直接解释这些代码就行了,这样省去了Flex语法器进行语法编译和大部分语法检查。

2.eAccelerator

D.客户端缓存

1.由浏览器实现

2.相关Header参数:

①Expires过期时间

②Cache-Control让网站发布者全面控制内容,并定位过期时间的限制(max-age=[秒],缓存过期时间;s-maxage=[秒]类似于max-age,应用于共享缓存;public标记认证内容也可以被缓存;no-cache强制每次请求直接发送给源服务器,而不经过本地缓存版本的校验;no-store强制缓存在任何情况下都不要保留副本;must-revalidate每次使用该资源都需要确认新鲜性;proxy-pevalidate和maust-revalidate类似,只对缓存代理服务器起作用;Last-Modified文档最后修改时间)

③ETag服务器生成唯一标识符ETag,每次请求的标签都会变化

3.HTML5中的Application Cache

E.Web服务器缓存

1.Apache缓存

2.Nginx缓存

https://github.com/zhangyue0503/php/blob/master/phphexinjishuyuzuijiashijian/7.php

九、Memcached使用与实践

A.安装及使用

1.特点:协议简单;基于libevent的事件处理;内置内存存储方式;采用不互相通信的分布式;

B.深入了解Memcached

1.使用多路复用I/O模型(如epoll、select等)

C.Memcached分布式布置方案

1.普通Hash分布

2.一致性Hash分布

https://github.com/zhangyue0503/php/blob/master/phphexinjishuyuzuijiashijian/8.php

十、Redis使用与实践

A.数据类型

1.String:不能有\n

2.List:可以做消息队列

3.Set:无序集合,快速查找元素是否存在,用于记录一些不重复的数据

4.Sorted Set:有序集合,通过一个double类型的整数score进行排序,可以构建具有优先级的队列

5.Hash:key对应一个HashTable,适合存储对象

B.事务处理

1.只能保证一个客户端连接发起事务中的命令可以连续执行,而中间不会插入其他客户端连接的命令

C.持久化

1.内存快照:将内存中的数据以快照方式写入二进制文件中,使用save命令

2.日志追加:(aof)方式是把增加、修改数据的命令通过write函数追加到文件尾部,重启时读取appendonly.aof文件中的所有命令并且执行,从而把数据写入内存

D.虚拟内存

1.把很少使用的value保存到磁盘中,把 value对应的key保存在内存中

https://github.com/zhangyue0503/php/blob/master/phphexinjishuyuzuijiashijian/9.php

十一、高性能网站架构方案

数据库会降低应用性能:

①虽然缓存可以降低数据库的访问次数,但缓存过期后仍然需要访问数据库

②数据库的写操作通常不能引入缓存策略

③没有搭建缓存环境,而直接对数据库操作

A.如何优化网站响应时间

1.优化响应时间

①减少http请求:将多个图片合并成为一个独立的HTTP请求;合并JS脚本和CSS样式文件;利用浏览器的Cache功能

②动态内容静态化

③优化数据库

④使用负载均衡

⑤使用缓存

2.吞吐率:单位时间内服务器处理的请求数,使用“reqs/s”(服务器每秒请求的数量)表示

3.压力测试:LoadRunner、JMeter、ApacheBench等

4.持久连接:又称长连接(Keep-Alive),指TCP连接中持续发送多份数据而不断开的连接。

发出的HTTP请求头包含Connection:Keep-Alive,Apache中打开KeepAlive on,Apache过期时间KeepAliveTimeout 20,长链接不是正效应,有可能影响服务器的并发性能

B.MySQL响应速度提高方案:HandlerSocket

C.MySQL稳定性提高方案:主从复制

1.优点:增加健壮性;优化响应时间;在从库备份过程中,主库持续更新;

2.工作原理:通过Binlog Dump线程将binlog日志传给从库;从库通过一个I/O线程将binlog日志中的更新操作复制到Relay Log中继日志文件;从库再通过另一个SQL线程将Relay Log中的操作进行执行;

D.Web应用回事方案:Varnish

1.代理:介于客户端和Web服务器之间的另一台服务器称为代理服务器,浏览器不直接到Web服务器取回网页,而向你代理服务器发出请求,信号先送到代理服务器,由代理服务器取回浏览器所需要信息并传送给浏览器。

2.反向代理:与代理的对象不同,对象是服务器端程序。通过反向代理服务器间接访问Web服务器,从而把后端代理服务器隐藏。包括Squid、Varnish以及nginx。

E.异步计算方案:Gearman

1.包括三个部分:Client,创建并发起一个Job请求;Job Server,找到合适的Worker,并把Job交给Worker;Worker,执行Job。

https://github.com/zhangyue0503/php/blob/master/phphexinjishuyuzuijiashijian/10.php

https://github.com/zhangyue0503/php/blob/master/phphexinjishuyuzuijiashijian/10worker.php

十二、代码调试和测试

A.调试PHP代码

echo、print_r()、var_dump()、debug_zval_dump()、debug_print_backtrace()以及使用Xdebug和IDE配合

B.前端调试

Firebug、Fiddler

C.日志管理

1.PHP日志:php.ini中,Log_errors = ON;error_log=path

2.Apache服务器日志:httpd.conf中,ErrorLog “path”;CustomLog “path” common

3.MySQL日志:错误日志;二进制日志(binLog),包含所有更新数据或者已经潜在更新数据的所有语句;查询日志,记录所有操作,影响性能;慢查询日志;

D.代码性能测试技术

1.Xdebug(WinCacheGrind)

2.性能测试注意事项:如果进行对比测试,首先应保证可比性;排队不相关因素;过多与过少(样本量与次数);考虑热启动时间;指标的全面性;关于时间精度(Linux精度高);

E.单元测试

PHPUnit

常用方法:setUp();setUpBeforeClass();tearDown;tearDownAfterClass;markTestSkipped

常用注解:@depends,定义一种依赖关系,即一个测试方法的参数内容和是否会运行依赖于另外一个测试方法的结果;@test,只有以test字符开头的方法才会被测试;@assert,断言;

F.压力测试

1.JMeter

术语:线程组,测试里每个任务都要线程处理;取样器,可以认为所有测试任务都由取样器承担;断言,对取样器返回的请求结果给出判断;监听器,对取样器的请求结果进行显示;

2.压力测试MySQL

mysqlslap命令,JMeter,Badboy

https://github.com/zhangyue0503/php/blob/master/phphexinjishuyuzuijiashijian/11.php

十三、Hash算法与数据库实现

Hash表(HashTable)又称散列表,通过把关键字Key映射到数组中的一个位置来访问记录,以加快查找的速度。这个映射函数称为Hash函数,存放记录的数组称为Hash表。

A.Hash函数

1.作用是把做生意长度的输入,通过Hash算法变成固定长度的输出。这种转换是一种压缩映射,也方法是Hash值的空间通常远小球输入的空间。

B.Hash算法

1.直接取余法:直接用关键字k除以Hash表的大小m取余数,h(k) = k mod m;

2.乘积取整法:首先使用关键字k乘以一个常数A(0<A<1),并制取出kA的小数部分。然后用Hash表大小m乘以这个值,再取整数部分即可。h(k) = floor(m*(kA mod 1))

3.经典Hash算法Times33:比较有有名的ELFHash、APHash和Time33等。Time33的思路就是不断乘以33,其效率和随机性都非常好,广泛运用于多个开源项目,如Apache、Perl和PHP等。

C.Hash表

1.实现步骤:创建一个固定大小的数组用于存放数据;设计一个Hash函数;通过Hash函数把关键字映射到数组的某个位置,并在此位置上进行数据存取。

2.SplFixedArray,更接近C语言的数组,效率更高。必须 开启SPL扩展。

3.解决冲突常用的方法有:开放定址法和拉链法。

D.一个小型数据库的实现

1.pack函数,把数据装入一个二进制字符串;umpack,从二进制字符串对数据进行解包;

https://github.com/zhangyue0503/php/blob/master/phphexinjishuyuzuijiashijian/12.php

十四、PHP编码规范

A.文件格式

1.文件标记:使用完事的PHP标签,不建议使用短标签;只含有PHP的文件在结尾处忽略?>

2.文件和目录命名:使用有意义的英文命名,使用驼峰法

3.文件目录结构:合理分配目录

B.命名规范

1.变量命名:驼峰法;全局变量两边加“_”,中间驼峰;普通变量,建议变量前加类型的前缀;函数名,有意义,尽量缩写;

2.类及接口命名:类,以大写字母开头,多个单词驼峰,与文件名保持一致,程序中唯一,抽象类以Abstract开头;接口,和类相同的规则,但命名前加i字符,尽量保持和实现它的类命名一致;

3.数据库命名:数据表,使用小写字母,统一前缀,使用“_”间隔;字段命名,使用小写,驼峰,如有必要给常用字段加上表名首字母作为前缀,避免使用关键字和保留字;存储过程、触发器、event以及视图的命名在表的命名规则的基础上,存储过程以proc_开头,触发器以tri_开头,Event调度以event_开头,视图以view_开头;

4.习惯与约定:循环体中使用I-N字母作为循环体中的变量命名;

C.注释规范

1.程序注释:写在被注释代码前面,单行写行尾;大段注释,用/**/,单行用//;注释不宜太多;代码注释应该描述为什么,而不是做什么;

2.文件注释:包含本程序的描述;包含作者;包含项目名称;包含文件的名称;包含书写日期;包含版本信息;包含重要的使用说明;

3.类/接口注释:尽量简洁

4.方法和函数注释:写在前面,标明信息主要是可见性、参数类型和返回值的类型

5.IDE标注

D.代码风格

1.缩进和空格:使用4个空格作为缩进,变量赋值时等号左右留出空格;

2.语句断行:保证程序语句一行就是一句,尽量不要使一行的代码太长保持在80个字符以内,如果太长使用.=断行书写,执行sql不要在函数内写SQL语句

3.更好的习惯:使用PHP中已经存在的常量,在echo中使用逗号连接字符串,更详尽的注释,不要滥用语法糖;

原文发布于微信公众号 - 硬核项目经理(fullstackpm)

原文发表时间:2019-05-14

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券