近来看了许多PHP面试题,有的题目有答案,有的没有。还是决心全部记录一下,部分答案是借鉴网上的资料,部分是自己总结。有的题目可能有冗余,答案不是很细化,就当作自己熟练题目,另外,也可以让大家借鉴,哪里总结的不完整或不正确,还望指正。
答:选取合适的字段属性 ; 尽量把字段设置为not null;尽量少用join,少用子查询,如果有多表业务逻辑需求,尽量使用程序解决数据整合问题,单表查询数据,然后整合,将压力放在程序上(服务层),而不是数据层;使用UNION代替手动创建的临时表; 锁定表;合理使用索引(注意sql语句的写法,尽量避免索引失效);少用like这种查询语句,虽然很方便,但是是以消耗系统性能为代价的。
2. mysql 数据库表的类型有哪些?
答: MyISAM、InnoDB、HEAP、BOB、ARCHIVE、CSV等
常用的2种:MyISAM、InnoDB
MyISAM:成熟、稳定、易于管理,快速读取。一些功能不支持(事务等),表级锁。
InnoDB:支持事务、外键等特性、数据行锁定。空间占用大,不支持全文索引等。
如何预防sql注入?
答: 目前好多框架中自带的数据库操作model已经集成了sql注入预防功能,底层一般都是使用pdo面向对象预编译执行。
如果使用mysqli原生连接的话,可以使用过滤函数,过滤字符,转义字符等方法。
例如:strip_tags(),mysql_escape_string(),htmlspecialchars()等函数进行过滤
谈谈悲观锁与乐观锁的区别与联系?
答:
悲观锁:顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。
传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
乐观锁: 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。
乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。
悲观锁和乐观锁的区别:
两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果经常产生冲突,上层应用会不断的进行retry,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适。
如何处理系统的高并发,高负载?
答:
1. html文件尽量静态化
2. 客户端(一般是APP与浏览器) 尽量使用本地缓存 ,减少调用服务端接口次数
3. 客户端(一般是APP与浏览器) 限制访问接口频次(例如某个按钮连续被点击.......)
4. 图片服务器分离,把图片,视频资源放在单独的文件服务器上,减少主服务器的网络开销,例如放在阿里云的oss上(很方便,例如图片的压缩,裁剪,视频的封面图获取等等操作很方便,当然oss也有一定的费用.....)
5. 数据库集群,可以读写分离,主从复制。
6. 使用缓存,例如redis,在服务层与数据层中间加入缓存层,让请求尽最大的可能访问缓存(命中缓存),减少数据库的访问
7. 使用负载均衡,可以使用nginx作为反向代理负载均衡器,apache集群(当然并不是只有nginx这一种方式),因为nginx处理高并发比较好,apache的稳定性又比较好,二者结合,比较合适。
8. 站点层拦截,例如,同一个用户,同一个请求,几秒之内只能请求几次,可以使用缓存实现,使用缓存记录时间信息,(相当于限流,限速....), 此种限制方式,建议还是在服务端的接口入口处加上吧,因为和我们后端合作的客户端(app,web),往往不会考虑这些负载啊,速度啊,压力之类的事情,往往调用接口不合理(如果客户端没有架构师指导的话)。
session 与cookie的区别?
答:
cookie数据存放在第三方应用的浏览器上,session数据放在服务器上。
cookie不是很安全,别人可以分析存放在本地的COOKIE,进行COOKIE欺骗,考虑到安全应当使用session。
session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用COOKIE。
单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
session的过期时间,指的是静默时间,例如:某个用户的登录session设置的是20分钟过期时间,如果前18分钟用户都没有任何操作,在第19分钟访问了session,有了操作,那么,过期时间重新计算,从0开始计数。而cookie设置了20分钟,无论有无访问,20分钟到了,就是过期了
另外 session可以设置存放形式,默认是文件(file)形式,可以设置为user形式,将session放在缓存或数据库中。
php的魔术方法有哪些?
答:
__construct() 实例化对象时被调用,当__construct和以类名为函数名的函数同时存在时,__construct将被调用,另一个不被调用。
__destruct() 当删除一个对象或对象操作终止时被调用。
__call() 对象调用某个方法,若方法存在,则直接调用;若不存在,则会去调用__call函数。(此方法工作中很常见,很常用)
__get() 读取一个对象的属性时,若属性存在,则直接返回属性值;若不存在,则会调用__get函数。
__set() 设置一个对象的属性时,若属性存在,则直接赋值;若不存在,则会调用__set函数。
__toString() 打印一个对象的时被调用。如echo $obj;或print $ob
__clone() 克隆对象时被调用。如:$t=new Test();$t1=clone $t;
__sleep() serialize(序列化)之前被调用。若对象比较大,想删减一点东东再序列化,可考虑一下此函数。
__wakeup() unserialize(反序列化)时被调用,做些对象的初始化工作。
__isset() 检测对象一个不存在的属性时被调用。如:isset($c->name)。
__unset() 删除对象一个不存在的属性时被触发。如:unset($c->name)。
__set_state() 调用var_export时,被调用。用__set_state的返回值做为var_export的返回值。
__autoload() 实例化一个对象时,如果对应的类不存在,则该方法被调用。(此方法,工作中很常用,尤其自己封一个框架用的时候,避免需要引入很多类文件,可以使用此方法)
请手写一个冒泡排序
答:直接上代码了,我写的这个方法,还可以优化…
/**
* 冒泡排序
* TODO 核心思想,相邻的2个值,进行比较,如果后一个值大于前一个值,将此时2个位置的值,进行互换
*/
function maoPaoSort($arr){
if(!is_array($arr)){
return false;
}
$len = count($arr);
$lenSon = $len-1;
for($i=0;$i<$len;$i++){
for($j=0;$j<$lenSon;$j++){
//TODO 每次进来,就可以将比较大的值向上冒一位
if($arr[$j]>$arr[$j+1]){
//将大的值,临时保存起来
$tempData = $arr[$j];
$arr[$j] = $arr[$j+1];
$arr[$j+1] = $tempData;
}
}
}
return $arr;
$arr = [100,80,70,200,60,40,90];
var_dump(maoPaoSort($arr))
redis 与memcacahe、mongoDB的区别与联系?
答:
都是非关系型数据库,性能都非常高,但是mongoDB和memcache、redis是不同的两种类型。后两者主要用于数据的缓存,前者主要用在查询和储存大数据方面,是最接近数据库的文档型的非关系数据库。
从数据存储位置上来分,memcache的数据存在内存中,而redis既可以存储在内存中,也可以存储的到磁盘中,达到持久化存储的功能,memcache一旦断电,数据全部丢失,redis可以利用快照和AOF把数据存到磁盘中,当恢复时又从磁盘中读取到内存中,当物理内存使用完毕后,可以把数据写入到磁盘中。
从存储数据的类型上来分,memcache和redis存储的方式都是键值对,只不过redis值的类型比较丰富,有string(字符串),hash(哈希),list(列表),set(集合)zset(有序集合),而memcache主要存储的是字符串
从架构层次来分,Redis支持master-slave(主—从)模式应用,memcache支持分布式。
从存储数据的大小上来分,Redis单个value的最大限制是1GB,memcached只能保存1MB的数据。但是Memcache在存储100K以上的数据,性能稍微好一点。
另外redis只支持单核,memcache可以支持多核,当然关于redis取代memcache的说法,在一般情况下,两者性能都很高,在大多的业务场景选择上,redis的选择可能更加具有优势,因为其存储的类型相对比较丰富,例如队列,在工作中比较常用。
$this和self、parent 这3个此分别代表什么,在哪些场景下使用?
$this 当前对象
self 当前类
parent 当前类的父类
$this 在当前类中使用,使用->调用属性和方法。
self 也在当前类中使用,不过需要使用::调用。
parent 在类中使用。
redis单线程有什么优势与缺点?
优点:
1. 代码更清晰,处理逻辑更简单
2. 不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗
3. 不存在多进程或者多线程导致的切换而消耗CPU
缺点:
因为是单线程的,无法发挥多核cpu的优势,容易阻塞。
php 的运行模式有哪些?
答:
1)cgi 通用网关接口(Common Gateway Interface))
2) fast-cgi 常驻 (long-live) 型的 CGI
3) cli 命令行运行 (Command Line Interface)
4)web模块模式 (apache等web服务器运行的模块模式)
具体参考资料:https://www.cnblogs.com/liangxiaofeng/p/5339557.html
答:
Nginx:
轻量级,采用 C 进行编写,同样的 web 服务,会占用更少的内存及资源
抗并发,nginx 以 epoll and kqueue 作为开发模型,处理请求是异步非阻塞的,负载能力比 apache 高很多,而 apache 则是阻塞型的。在高并发下 nginx 能保持低资源低消耗高性能 ,而 apache 在 PHP 处理慢或者前端压力很大的情况下,很容易出现进程数飙升,从而拒绝服务的现象。
nginx 处理静态文件能力较好
nginx 的设计高度模块化,编写模块相对简单
nginx 配置简洁,正则配置让很多事情变得简单,而且改完配置能使用 -t 测试配置有没有问题,apache 配置复杂 ,重启的时候发现配置出错了,会很崩溃(这一点确实是深受其害啊...........)
nginx 作为负载均衡服务器,支持 7 层负载均衡
nginx 本身就是一个反向代理服务器,而且可以作为非常优秀的邮件代理服务器
Apache:
apache 的 rewrite 比 nginx 强大,在 rewrite 频繁的情况下,考虑用 apache
apache 模块超多,基本想到的都可以找到
apache 更为成熟,少 bug ,nginx 的 bug 相对较多
apache 稳定性特别好
apache 对 PHP 支持比较简单,nginx 需要配合其他后端用
apache 在处理动态请求有优势,nginx 在这方面是鸡肋,一般动态请求要 apache 去做,nginx 适合静态和反向。
总结:
两者最核心的区别在于 apache 是同步多进程模型,一个连接对应一个进程,而 nginx 是异步的,多个连接(万级别)可以对应一个进程
一般来说,需要性能的 web 服务,用 nginx 。如果不需要性能只求稳定,更考虑 apache ,后者的各种功能模块实现得比前者,例如 ssl 的模块就比前者好,可配置项多。epoll(freebsd 上是 kqueue ) 网络 IO 模型是 nginx 处理性能高的根本理由,但并不是所有的情况下都是 epoll 大获全胜的,如果本身提供静态服务的就只有寥寥几个文件,apache 的 select 模型或许比 epoll 更高性能。当然,这只是根据网络 IO 模型的原理作的一个假设,真正的应用还是需要实测了再说的。
更为通用的方案是,前端 nginx 抗并发,后端 apache 集群,配合起来会更好。
14.nginx的epoll模型的介绍以及io多路复用模型
连接:http://www.mamicode.com/info-detail-2283798.html
此方法,个人认为对于mysql索引优化很有用处,可以作为其中一个判断依据,去判断sql语句是否合理。
答:使用explain 关键字
例如: select * from bu_course_lesson => explain select * from bu_course_lesson 通过查看结果的type值可以看出,如果type是all那么就没有使用索引
16 . foreach 与for循环的对比
对于for循环来说,每一次都要判断$i 是否到达长度,小于继续,否则终止循环;
对于foreach来说,它依赖于 IEnumerable(迭代器), 第一次 var a in GetList() 时 调用 GetEnumerator 返回第一个对象 并 赋给a,以后每次再执行 var a in GetList() 的时候 调用 MoveNext.直到循环结束,期间GetList()方法只执行一次.
在固定长度或长度不需要计算的时候for循环效率高于foreach.
在不确定长度,或计算长度有性能损耗的时候,用foreach比较方便.
并且foreach的时候会锁定集合中的对象.期间不能修改.
php的fpm进程管理器的三种模式,优缺点是什么?
https://blog.csdn.net/tzhennan/article/details/84920895
18 .serialize() /unserialize()函数的作用?
serialize()和unserialize()在php手册上的解释是:
serialize — 产生一个可存储的值的表示,返回值为字符串,此字符串包含了表示 value 的字节流,不丢失其类型和结构,可以存储于任何地方。
unserialize — 从已存储的表示中创建 PHP 的值
这2个方法在数组或对象放入缓存时,推介使用。例如将数组放入redis缓存,应该将数组序列化,再放入,不建议使用json_encode() 方法。
PHP处理上传文件信息数组中的文件类型 F I L E S [ ‘ t y p e ’ ] 由 客 户 端 浏 览 器 提 供 , 有 可 能 是 黑 客 伪 造 的 信 息 , 请 写 一 个 函 数 来 确 保 用 户 上 传 的 图 像 文 件 类 型 真 实 可 靠 ? 答 : 用 g e t i m a g e s i z e ( ) 函 数 来 判 断 上 传 图 片 的 类 型 比 _FILES[‘type’]由客户端浏览器提供,有可能是黑客伪造的信息,请写一个函数来确保用户上传的图像文件类型真实可靠? 答:用getimagesize()函数来判断上传图片的类型比 FILES[‘type’]由客户端浏览器提供,有可能是黑客伪造的信息,请写一个函数来确保用户上传的图像文件类型真实可靠?答:用getimagesize()函数来判断上传图片的类型比_FILES函数的type更可靠。同一个文件,使用不同的浏览器php返回的type类型是不一样的,由浏览器提供type类型的话,就有可能被黑客利用向服务器提交一个伪装撑图片后缀的可执行文件。
20 .写出、你能想到的所有HTTP返回状态值,并说明用途?
答:
200 (成功) 服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。
301 (永久移动) 请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。
302 (临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
401 (未授权) 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。
403 (禁止) 服务器拒绝请求。
404 (未找到) 服务器找不到请求的网页。
500 (服务器内部错误) 服务器遇到错误,无法完成请求。
501 (尚未实施) 服务器不具备完成请求的功能。 例如,服务器无法识别请求方法时可能会返回此代码。
502 (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。
503 (服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。
504 (网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求。
505 (HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。
php 的垃圾回收机制是什么样的?
答:PHP可以自动进行内存管理,清除不再需要的对象。PHP使用了引用计数(referencecounting)这种单纯的垃圾回收(garbagecollection)机制。每个对象都内含一个引用计数器,每个reference连接到对象,计数器加1。当reference离开生存空间或被设为NULL,计数器减1。当某个对象的引用计数器为零时,PHP知道你将不再需要使用这个对象,释放其所占的内存空间。
写一个函数判断输入的是不是整数
//判断数据是不是整数
function isInt(KaTeX parse error: Expected '}', got 'EOF' at end of input: … if(empty(data)){
return false;
}
if(!is_numeric( d a t a ) ∣ ∣ s t r p o s ( data) || strpos( data)∣∣strpos(data,".")!==false){
return false;
}
return true;
}
is_numeric() 检测是否是数字或数字字符串
strpos() 字符串中某个字符第一次出现的位置,没有找到,返回false