前两天出去面试了,结果让我有点意外,我居然跪在了很简单的几道基础题上,使用框架开发项目时间久了,果然就如当时在学校老师说的那样,基础全忘光了,写项目的业务模块倒是熟练了很多,反而把最基本的东西忘的一干二净,刚好最近找工作也要复习,不如就把面试中遇到的面试题自己做一个详解,同时根据问到的知识点进行一个相关知识点的补充。
飞飞当时给我说过一句话挺有趣的,“面试一万个人然后招一个人,你最后没有面试上,就是自己太菜,不用管自己在那9999个人里面排多少位,这不重要,重要的是,你不是第一。”虽然这句话看起来说的有一些绝对,但还是有一些道理的,菜就是菜,慢慢补呗。
写出Session与Cookie区别
考点:PHP会话控制技术
为什么需要会话控制技术?
HTTP是无状态协议,没有一个内建机制维护两个事物之间的状态。同一个用户请求两次HTTP请求时,HTTP协议不会认为这两次请求都来自同一个用户,会当成两个独立的请求来处理。也就没有办法保持用户的登陆状态,所以会话控制技术的核心思想是 允许客户端跟踪服务端做出的连续请求 ,从而完成登陆状态的保持。
Cookie: 服务器发送给客户端的片段信息, 存储在客户端浏览器的内存或硬盘中的一种技术。
- 写Cookie: setcookie(name,value,expire,path,domain,secure)
- name:Cookie名称,可以使用 ‘a[b]’
- value:Cookie值
- expire:Unix时间戳,以秒为单位,如果不设置,则在浏览器关闭时过期
- path:有效服务器路径,设置为 ‘/‘ 时,对整个域名domain有效,如果设置为 ‘/foo/‘ ,则仅对domain中/foo/目录及其子目录有效(例如:/foo/ban/)
- domain:Cookie的有效域名/子域名,设置成子域名(例如:’www.example.com’ ),会使Cookie对这子域名和他的三级域名有效(例如:w2.www.example.com)。要让Cookie对整个域名有效,设置顶级域名就行了(例如:example.com)
- 读取Cookie: $_COOKIE
- 删除Cookie: setcookie(name,’’,time()-1) ,把Cookie设为过期即可
Cookie优缺点:
优点: 存储在客户端不会浪费服务器资源 缺点: 由于数据存储在客户端,不建议将一些敏感重要的数据使用Cookie存储。客户端有权限禁用掉Cookie的使用。
Session: 将用户的数据 存储在服务器 当中,用户无法禁止掉Session使用,但 Session不是完全脱离Cookie的 。Session是通过服务器客户端Cookie带过来的SESSIONID来确定用户数据的,如果Cookie被禁用,需要通过URL传递SESSIONID的形式保存SESSION的状态。
Session的使用
- 开启Session:
session_start()
- 使用Session:
$_SESSION
直接操作SESSION数组就可以 - 清空Session:
$_SESSION=[]
或$_SESSION = null
- 删除Session(包括文件和Cookie):
session_destroy()
Session的配置 php.ini
文件
session.auto_start
是否自动开启Sessionsession.cookie_domain
设置Session的有效域名session.cookie_lifetime
设置的cookie有效时间,是从创建了这个cookie时开始计算,不会因为操作而刷新session.cookit_path
设置session有效服务器路径session.name
存储在客户端的Cookit的名称,session.save_path
设置session在服务器存储路径session.use_cookies
是否使用Cookie传递sessionsession.use_trans_sid
是否允许SESSIONID通过URL明文传输session.gc_probability
清理多少次垃圾session.gc_divisor
每访问多少次session.gc_maxlifetime
设置的session的最大生命周期session.save_handler
设置存储方式,可以存储到Redis中或MySQL中,默认是’files’类型,即文件存储
Session垃圾回收机制
Session是存储在服务器上的,如果用户没有走退出程序而是直接关闭掉了浏览器,则Session文件会永久的保存在服务器上,时间长了会撑满内存,这个适合就需要使用Session的垃圾回收机制,大概流程是这样的:
- 当用户长时间没有再次访问Session,比如刷新、修改、添加等操作(时间根据:
session.gc_maxlifetime
设置的秒数,默认1440,PHP5默认1500),超过这个时间 则Session将会被设为过期的“垃圾文件” - 当Session被设置为垃圾文件时,PHP每被请求设定次数 (次数根据:
session.gc_divisor
设置的次数,默认1000),清除设定个数文件(session.gc_probability
默认是1次,也就是说每访问1000次清空一个过期文件),不建议把清除次数设置的特别小,会消耗服务器资源
优点: 数据存储在服务器,相比Cookie比较更安全。 缺点: 占用服务器资源,如果垃圾回收机制设置不合理,会撑满服务器硬盘。
Cookie被禁用时如何传递SESSIONID
<!-- 使用session_name()和session_id()传递 -->
<a href="<?php echo session_name().'='.session_id()?>">下一个页面</a>
<!-- 使用SID常量传递,SID比较智能,比较推荐使用这个-->
<!-- 在Cookie开启的时候,值为空,Cookie禁用的时候才会输出 -->
<a href="<?php echo SID?>">下一个页面</a>
Session存储共享(Redis/MySQL/Memcache)
如果需要使用多台服务器的话,直接将Session存储到其中一台服务器的时候,可能下次访问的时候就是另一台服务器了,这种情况下Session因为不能共享的原因会导致用户的Session信息无法共享在其他的服务器上。这时需要使用 `session_set_save_handler`设置用户自定义会话存储函数。
写出下列代码输出结果
<?php
var_dump(empty($a));
var_dump(isset($a));
var_dump(is_null($a));
empty($a)
输出 `bool(true)` , 判断一个变量是否为空,当变量不存在时,或它的值等同于false时,那么它就会被认为不存在, empty() 并不会产生警告 , empty() 本质上与 !isset($var) || $var == false 等价
isset($a)
输出 `bool(fasle)` ,判断变量是否设置且非NULL,使用 unset() 释放变量后,使用 isset() 结果为false。 isset() 可以传递多个变量,只有当所有变量都被设置时才会返回TRUE,计算过程从左往右,中途遇到没有设置的变量则不会继续往后计算。<br />**is_null($a)**
输出 `bool(true)` ,检测变量是否为NULL,以下三种情况变量被认为是NULL:
- 赋值为NULL
- 尚未被复制 (只是被声明了)
- 被 unset() 掉的变量
使用正则验证邮箱的正确性
我写的面试答案:[0-9a-zA-Z]+@[0-9a-zA-Z]{2,}.[0-9a-zA-Z]{2,4}
太久不用正则的原因导致我写的这个正则,用到是能用,但是写的过于繁琐,还有就是小部分情况下无法验证。错误: 使用.
的时候需要转义,否则匹配不到 “.” 会出现错误
改良后的写法:^\w+@\w{2,}\.\w{2,4}$
正则表达式的所用:分割
查找
匹配
替换
关于正则的用法补充:
- 分隔符
/
正斜线#
hash符号~
取反符号
- 通用原子
\d
十进制的0-9\D
除了十进制的0-9,可以理解为\d
取反\w
数字字母下划线\W
除了数字字母下划线,可理解为\w
取反\s
空白字符(空格)\S
除了空白字符,可理解为\s
取反
- 元字符
.
除了换行符以外的任意字符*
匹配前面的内容,零次、一次、多次?
匹配前面的内容,零次、一次^
必须以此开头$
必须以此结尾+
出现一次或多次{n}
只能出现N次{n,}
至少出现N次{n,m}
至少出现N次,最多出现M次[]
或,比如[123]
表示 1或2或3()
表示一个整体[^123]
表示 除了1 除了2 除了3|
表示或的意思[-]
范围值,例如[0-9]
- 模式修正符
i
不区分大小写m
每一行分别匹配s
修正换行符,如果由换行符就需要使用这个修正,否则匹配不上U
取消贪婪模式x
忽略模式中的空白字符A
必须以这个模式开头D
修正对\n
的忽略u
utf-8编码,中文匹配时有用
补充一些常用正则规则:
- 验证手机号:
^1[3456789]\d{9}$
- 验证身份证号:
^\d{17}[\dxX]$
设计一个无限级分类表,并写出查询代码
什么是无限级分类?
无限分类就是在一个分类下面可以创建多个子类,而其子类下面同样可以创建不同子类,如此往复,没有终点。
使用无限分类一个可以做分类的下拉列表,也可以做分类的面包屑导航。
以父ID实现的无限分类
使用递归算法。表中一个字段id,一个字段pid(父ID),这样可以根据WHERE id = pid 来查出上一层内容,运用递归至顶层。
表名:cate
字段名 | 类型 |
---|---|
id | int(11) 主键索引 无符号 |
pid | int(11) 无符号 父级id,根据这个判断父级是谁 |
title | var_char() 分类名称 |
代码实现:
<?php
$dsn="mysql:host=127.0.0.1;port=3306;dbname=test;charset=utf8mb4;";
$pdo=new PDO($dsn,'root','root');
$sql='SELECT * FROM `cate` Order BY pid';
$result=$pdo->query($sql,PDO::FETCH_OBJ);
$categories =[];
// 循环结果集 按照层级拼
foreach($result as $value){
$categories[$value->pid][]=$value;
}
$tree=[];
// 拼接树形结构
function catetree($categories,$n){
global $tree;
// 如果由子类再循环
if(isset($categories[$n])){
foreach($categories[$n] as $category){
// 几层就输出几个
$tree[] = '├'.str_repeat('-',$n).$category->title;
catetree($categories,$category->id);
}
}
}
// 调用函数
catetree($categories,0);
// 输出结果
var_dump($tree);
/**
array (size=10)
0 => string '├新闻' (length=9)
1 => string '├-国内新闻' (length=16)
2 => string '├---北京新闻' (length=18)
3 => string '├-国际新闻' (length=16)
4 => string '├----美国新闻' (length=19)
5 => string '├图片' (length=9)
6 => string '├--风景图片' (length=17)
7 => string '├--美女图片' (length=17)
8 => string '├-------日韩明星' (length=22)
9 => string '├---------日本电影' (length=24)
**/
?>
MySQL的InnoDB和MyISAM引擎区别,分别适合那些场景?
- InooDB引擎
- 支持事务,性能优秀
- 数据存储在共享表空间,可通过配置分开
- 对于主键查询性能高于其他引擎
- 读取数据时自动在内存构建Hash索引,插入数据时自动构建插入缓冲区
- 通过一些机制和工具支持真正的热备份
- 支持崩溃后的安全恢复
- 支持行级锁,但没有命中索引的情况下依然会使用表锁
- 支持外键
- MyISAM引擎
- 5.1版本之前MyISAM引擎是默认的存储引擎
- 拥有全文索引、空间函数和压缩
- 不支持事务和行级锁,不支持崩溃后的安全恢复
- 表存储的两个文件MYD和MTI
- 设计简单,再某些场景下性能会很好
InnoDB 适用场景: 需要事务的操作;更新数据需要使用行级锁;大数据量读写。 MyISAM适用场景: 不需要事务的操作;批量插入快;更新少;统计和读取频繁。
Redis常用类型,分别适合那些场景
String(字符串)
特点:字符串的一个常见用途就是用来缓存用户信息,我们将用户信息结构体使用JSON序列化成字符串,然后将序列化后的字符串塞进Redis来缓存,取用户信息的时候再经过一次反序列化过程。
Hash(哈希)
特点:Hash是一个键值对(K/V)合集,特别适合用于存储对象。
相比字符串序列化的存储信息更加直观。更新和获取数据时不需要像字符串那样全部取出来,只需要取出或者写入需要的部分即可。但是哈希结构的存储消耗高于单个字符串。
list(列表)
特点:简单的字符串列表,按照插入的顺序进行排序
列表结构将常被用来做异步队列使用,将需要延后处理的任务结构体序列化成字符串,塞进Redis的列表,另一个线程通过轮询对列表中的数据进行处理。
set(集合)
特点:set是String的无序合集,和列表不同的是集合中不允许有重复的元素
集合适合用来存储某些活动的用户ID,因为有去重功能,可以保证同一个用户不会中奖两次。
黑名单/白名单功能,`sismember` 命令可以方便的判断这个条件是否存在于黑名单/白名单之中
zset(有序集合)
特点:保留了set中不允许有重复元素的特点,但不同的是Zset是可以排序的,与列表的索引下标作为排序依据不同,Zset可以给每个元素设置一个数字,作为排序依据。
适合用来做排行榜这类的功能,比如:
- 粉丝列表,根据粉丝关注时间来排序;
- 热搜榜单:根据热搜点击次数来排序
- 成绩榜单:根据学生的成绩分数排序
写出冒泡排序
冒泡排序很简单,就直接上代码吧
<?php
function Bubble(Array $arr){
$length=count($arr) - 1;
for ($i=0; $i < $length; $i++) {
for ($j=0; $j < $length; $j++) {
if($arr[$j] > $arr[$j+1]){
$temp=$arr[$j];
$arr[$j]=$arr[$j+1];
$arr[$j+1]=$temp;
}
}
}
return $arr;
}
// 设置一个数组
$arr=[5,3,6,8,1,2,4,9,7];
var_dump(Bubble($arr));