1. PHP 面试题

1. PHP 常用的超全局变量

  • $GLOBALS:包含了全部变量的全局数组,变量的名字就是数组的键;
  • $_SERVER:包含了诸如头信息(header) 、路径(path) 以及脚本位置(scrpit locations) 等等信息的数组。这个数组中的项目由 Web 服务器创建;
  • $_REQUEST:默认情况下包含了 $_GET$_POST$_COOKIE 的数组;
  • $_GET:获取 get 请求的参数值,在 HTML 的 form 标签上指定属性 method="GET"
  • $_POST:获取 post 请求的参数值,在 HTML 的 form 标签上指定属性 method="POST"
  • $_FILE:通过 HTTP POST 方式上传到当前脚本的项目的数组,在 HTML 的 form 标签上指定属性 enctype="multipart/form-data" ;
  • $_SESSION:当前脚本可用的 SESSION 变量的数组;
  • $_COOKIE:通过 HTTP Cookies 方式传递给当前脚本的变量的数组,通过 setcookie() 函数可以发送修改 Cookie 信息;

2. PHP中双引号和单引号的区别

  • 双引号解释变量,单引号不解释变量;
  • 双引号解释转义字符,单引号不解释转义字符;
  • 能使用单引号时尽量使用单引号,单引号效率比双引号高,因为双引号在执行的时候要先遍历一边,判断里面有没有变量,然后再进行操作,而单引号不需要判断。

3. isset() 和 empty() 区别

isset() 用于判断变量是否存在,可以传入多个变量,若其中一个不存在则返回 false;
empty() 用于判断变量是否为空为假,只可传入一个变量,如果为空或为假则返回 true;

4. PHP 冒泡排序实例

冒泡排序法的基本思想是:依次比较相邻的两个数,然后根据大小做出排序,直至最后两位数。由于过程中是小数往前放,大树往后放,相当于气泡上升,所以称作冒泡排序。
实际过程中可以根据自己需求反过来用,大树往前,小数往后。

  1. // 冒泡排序
  2. // 每次只对相邻的两位进行对比排序
  3. $arr = [18,11,1,15,2,35,55,12,17,65,23,48,56,22,5];
  4. for($i=0; $i < count($arr), $i++){
  5. for($j=0; $j < count($arr)-i-1; $j++){
  6. // 冒泡排序 相邻的两位进行对比,小的往前换一位,打的换到后面,下轮继续和下一位对比
  7. if($arr[$j] > $arr[$j+1]){
  8. $tmp = $arr[$j];
  9. $arr[$j] = $arr[$j+1];
  10. $arr[$j+1] = $tmp;
  11. }
  12. }
  13. }
// 选择排序
// 每次用一位对该位+1后面的所有数进行对比,直接把小的一位排到前面

$arr = [18,11,1,15,2,35,55,12,17,65,23,48,56,22,5];

for($i = 0; $i < count($arr); $i++){
  for($j = $i+1; $j<count($arr); $j++){
    if($arr[$i] > $arr[$j]){
      $tmp = $arr[$i];
      $arr[$i] = $arr[$j];
      $arr[$j] = $tmp;
    }
  }
}

5. PHP中传值和引用的区别,优缺点

传值:将变量对应内存中的值传递给其他变量或函数,如传递给函数,则函数内对值的改变不会影响到函数外的原变量。
传引用:将变量对应内存的内存地址传递给其他变量或函数,如传递函数,则函数内对值的改变会影响到函数外的原变量。
优缺点:传值时,PHP是复制值传递,对于特别大型的字符串和对象来说,性能开销会比较大,而传引用则不需要复制值,只是把对应值的内存地址交过去,相对来说性能开销会小很多。

6. Session 和 Cookie 的区别

  • Session
    • Session 存储在服务器端,安全性比 Cookie 高;
    • 因为 Session 存储在服务器端,每次读取 Session 都会对服务器造成一定的资源消耗;
    • Session 默认保存为文件,可以通过 php.ini 中的 session.save_path 来配置;
    • Session 依赖 Cookie 进行传递,如果 Cookie 被禁用,可以通过其他方式在需要共享 Session 的页面传递 SessionID 来进行 Session 共享。
    • 浏览器关闭后,服务器会有 Session 回收机制,自动删除过期 Session 。
  • Cookie
    • Cookie 存储在客户端,有被篡改的风险,安全性比 Session 低;
    • 因为 Cookie 存储在客户端,需要占用服务器资源空间;
    • Cookie 可以持久存储
    • Cookie 可以被用户主动禁用

7. PHP 中 include 和 require 的区别

  • require
    • require 是无条件包含,也就是如果一个流程里加入 require ,无论条件是否成立都会先执行 require ,实际上,是用文件的内容替换 require 语句;
    • require 引入文件时,如果碰到错误,会报致命错误,并停止运行下面的代码
    • require 没有返回值
  • include
    • include 是在用到的时候才会加载;
    • include 引入文件时,如果碰到错误,会报警告错误,并继续运行下面的代码
    • include 有返回值

8. PHP 中常用的数组函数

  • array_merge() :数组合并函数,把一个或多个数组合并为一个数组
  • sort() :以升序对数组排序
  • rsort() :以降序对数组排序
  • asort() :根据值,以升序对关联数组进行排序
  • ksort() :根据键,以升序对关联数组进行排序
  • arsort() :根据值,以降序对关联数组进行排序
  • krsort() :根据键,以降序对关联数组进行排序
  • count() :返回数组元素个数
  • array_unique() :去除数组重复的元素,保留第一个出现的,包括键和值
  • in_array() :检查数组中是否存在某个值
  • list() :将数组中的元素赋值给多个变量
  • shuffle() :打乱数组中的元素
  • array_keys() :获取数组的键,第二个参数可以获取指定元素的键
  • array_diff() :比较两个或多个数组,并返回差集数组,比较以第一个参数的数组为主,结果为去除掉 array1 中对比其他数组重复的元素后,得到的结果集素组
  • array_map() :为数组的每个元素应用回调函数
  • array_pop() :弹出数组中的最后一个元素,并返回被弹出的元素内容
  • array_push() :将一个或多个单元压入数组的末尾,并返回处理后的数组元素总数
  • array_shift() :移除数组中的第一个元素,并返回被删除元素的值。
  • array_rand() :从数组中随机去除一个或多个随机键
  • array_search() :从数组中搜索给定的值,如果成功则返回第一个匹配的键名
  • array_key_exists() :检查数组里是否有指定的键名。
  • array_chunk() :将一个数组分割成多个
  • array_filter() :使用回调函数过滤数组的元素,如果没有提供回调函数,将删除数组中的所有空元素。
  • array_flip() :交换数组中的键和值,如果同一个值出现多次,则保留最后出现的

9. Get 个 Post 的区别

  • Get
    • Get 是显示的,数据可以从 URL 上看到,传输的数据量小,安全性较低
  • Post
    • Post 是隐式传递的,将数据打包到了请求中,可以传输大量的数据,安全性较高

2. MySQL 面试题

1. MySQL 中 char 和 varchar 的区别

varchar 类型是可变长度;char 是固定长度;
查找时,char 的效率要高于 varchar 。因为 varchar 是非固定长度,必须先查找长度,然后在进行数据提取。

2. 什么是索引

索引时一种数据结构,能够帮助我们快速的检索数据库中的数据

3. 索引的优点和缺点

  • 优点:
    • 可以极大的提高数据的查询性能
    • 可以提高数据分组与排序的性能
  • 缺点:
    • 索引本身需要占用一定的存储空间,如果大量的使用索引,则索引文件会占用大量的磁盘空间;
    • 索引的创建于维护需要耗费一定的时间,随着数据量的不断增长,耗费的时间会越来越长;
    • 在执行 的操作时,MySQL 内部会对索引进行维护,也会消耗一定的维护时间;

4. 索引的创建原则

  • 尽量使用小的数据类型的字段来创建索引;
  • 尽量使用简单的数据类型的字段来创建索引;
  • 尽量不要在 NULL 值字段上创建索引

5. 索引的使用场景

  • 适合创建索引的场景

    • 数据表中的数据达到一定量级时,应为数据表适当添加索引
    • 与其它表进行关联的字段,并且经常进行关联查询,应当为连接字段添加索引
    • 作为 where 子句的条件判断字段,并且经常用来进行相等的比较操作的字段,应当添加索引
    • 作为 order by 语句的字段,并且经常用来执行排序操作的字段,应当添加索引
    • 作为搜索一定范围内的字段,并且经常用来执行查询操作,应当添加索引
  • 不适合创建索引的场景

    • 在查询数据时很少使用的列和字段不适合添加索引
    • 字段数据却别性较小的字段,如性别字段,不适合添加索引
    • 大数据类型的字段,如 TEXT 、 BLOB 、BIT 等数据类型的字段,不适合添加索引
    • 当某个表的数据需要非常频繁的修改,不适合创建索引
    • 查询时,不作为 where 子句 、order by 子句 group by 子句 的字段,不适合添加索引

6. MySQL 的索引有哪些类型

  • 主键索引
  • 唯一索引
  • 普通索引
  • 组合索引
  • 全文索引
  • 空间索引

7. MySQL 有哪些索引方法

  • B+ Tree 索引 : 在 B Tree 索引的基础上进行优化的结果,MySQL 中大部分存储引擎支持,MySQL 默认索引;
  • Hash 索引 :比较适合存储 Key-Value 型数据。查询 Key-Value 型数据时,会根据 Key 快速获取数据。但是 Hash 索引有一个弊端,即不适合根据某个数据范围来查询数据,并且无法利用索引完成排序。而且不支持多列联合索引的最左匹配原则;
  • R-Tree :空间索引,对于地理空间类型的数据来说,通常会使用 R-Tree 索引;
  • Full-Text :全文索引。MySQL 5.6 之前只支持 MyISAM 存储引擎,5.6开始,InnoDB 存储引擎开始支持全文索引;

8. B+Tree 和 Hash 索引的区别

  • Hash 索引不适合进行范围查询,更适合等值查询
  • Hash 索引无法利用索引来完成排序
  • Hash 索引不支持多列联合索引的最左匹配原则
  • 在有大量重复键值的情况下,Hash 索引效率低,会存在 Hash 碰撞问题

9. MySQL 的优化有哪些方法

  • 数据表优化方面:
    • 在创建数据表时,给表定义一个自增非空的主键,因为如果不创建的话,InnDB 会选择一个非空且唯一的列来代替,如果没有这样的列,InnDB就会隐式定义一个主键;
    • 选择合适的数据类型,例如可以使用 int 类型就不要用字符串类型,这样可以减少内存空间和磁盘空间的占用,也可以使查询和排序等操作效率更高。
    • 尽量将字段设置为 NOT NULL ,如果字段允许为 NULL ,会使的索引更复杂,甚至导致索引失效
    • 对于字段较多且部分字段查询频繁的表,可以将其中使用较少的字段进行分表处理,以此来提高表的查询效率
    • 对于经常需要联合查询的多个表,建立中间表,将需要经常联合查询的数据放入中间表中,将原来的联合查询改为对中间表的查询,以此来提高查询效率
    • 增加合理的冗余字段,以减少不必要的联合查询,以此来调高查询效率
  • 查询优化方面:
    • 开启 慢查询日志 ,通过日志定位查询时间过长的慢查询,然后通过 explain 来进一步分析
    • 使用 explain 语句来查看语句的执行计划,看查询语句是否正确的使用了索引,是否进行了全表扫描等情况,并以此来对查询语句和索引进行优化调整;
    • 尽量使用 JOIN 连表查询来代替嵌套查询(子查询),并且确保联合字段上有索引。子查询会创建一个临时表,在查询完成后还需要将临时表进行销毁;
    • 查询时,如果要查找的字段上有索引,最好直接写明查询字段,例如 select xx, xx from table ,而不是直接使用 select * 进行全查询,不然会导致 MySQL 回表查询,减慢查询效率;
    • 在 where 条件中,尤其是设置了索引的列条件上,不要使用运算和函数,这会导致 MySQL 在执行语句时,使用函数或运算先对该列数据进行运算后在执行查询导致索引失效,也降低了运行效率
    • 在 where 条件使用频繁的字段上添加索引,并且多个条件的话要注意是否符合索引的顺序,防止因为条件顺序不正确而导致索引不生效(索引的最左前缀原则);
    • 在使用 LIKE 关键字进行查询时,将“%”放在后面,例如 like xx%
    • 在 where 条件中,如果使用了 OR 关键字,则必须保证 OR 前后条件中列都在索引上,并且是独立索引,查询才会使用索引,可以使用 union(复合查询) 关键字来替换 OR
    • 在 where 条件中,
  • 索引优化方面:
    • 表数据较少的时候,不建议添加索引,会导致在数据插入和更新时效率变低;
    • 一个数据表中的索引不要太多,添加新索引的时候可以考虑是否能添加到已有的组合索引中;
    • 表中数据新增和更新频繁的数据表,而查询较少的表不适合添加索引
    • 创建索引时,应该选择值差异性较大的列
    • 在经常需要作为查询条件和排序条件的列上添加索引;
    • 创建组合索引的时候,需要注意最左匹配原则,以确保索引可以被正常使用
  • 数据库优化方面:
    • 读写分离
    • 主从复制
    • 查询缓存
    • 外部缓存(redis)

10. 索引失效的情况

  • 如果 where 条件中有 or 会导致索引失效,or 需要 左右两边的列都有独立索引
  • 使用组合索引时,没有按照最左匹配原则写查询条件
  • 如果列类型是字符串,则在查询条件中,值需要用引号包含起来,避免隐式数据类型转换导致不走索引
  • 如果 MySQL 的查询优化器认为全表扫描比使用索引快,则不走索引
  • 查询到的数量是表的大部分,也会导致不走索引

11. MySQL 三大范式

  • 第一范式
    • 要求数据表的每个字段的值都必须具备原子性,确保数据表中的每个字段的值都是不可再分解的原子值
  • 第二范式
    • 第二范式建立在第一范式的基础上,保证一张表只表述一件事,并且所有非关键字段都完全依赖于同一字段,不能产生部分依赖(涉及到数据的分表操作)
  • 第三范式
    • 在第二范式的基础上,保证每列都和主键直接相关,表中的每列字段应该直接对应主键并且不依赖其他中间字段

12. MySQL 常用存储引擎

  • InnoDB
    • 特点
      • 支持事务
      • 锁级别为行锁,比 MyISAM 村吃引擎支持更高的并发
      • 支持外键操作
      • 在索引存储上,索引和数据存储在同一个文件中,默认按照 B+Tree 组织索引的结构,同时主键索引的叶子节点存储完整的数据记录,非主键索引的叶子节点存储主键的值
      • MySQL 5.6 后默认使用 InnoDB 存储引擎,并且支持全文索引
      • 更够通过二进制日志恢复数据
  • MyISAM
    • 特点
      • 不支持事务
      • 锁级别为表锁,在要求高并发的场景下不太适合
      • 不支持外键
      • 在索引存储上,索引文件和数据文件分离
      • 支持全文索引
      • 如果数据文件损坏,难以恢复数据

13. MySQL 的锁机制

  • 表锁
    • 开销小,加锁快;
    • 不会出现死锁;
    • 锁定粒度大,发生锁冲突的概率最高。并发度最低
  • 行锁
    • 开销大,加锁慢;
    • 会出现死锁;
    • 锁定粒度小,发生锁冲突的概率最低,并发度最高
  • 页面锁
    • 开销和加锁事件介于表锁和行锁之间;
    • 会出现死锁;
    • 锁定粒度介于表锁和行锁之间,并发度一般

3. Redis 缓存 面试题

1. redis 支持哪些数据类型

  • String 字符串
    • redis 的基本类型,一个 key 对应一个字符串 value
  • Hash 哈希
    • 是一个键值(key=>value)对集合
  • List 列表
    • 列表是简单的字符串列表,按照插入顺序排序
  • set 集合
    • 集合是 String 类型的元素无序集合
  • zset 有序集合
    • 有序集合是 String 类型的元素的元素集合,且不允许重复,不同的是每个元素都会被关联一个 double 类型的分数,redis 通过分数来为集合中的成员进行从小到大的排序