【PHP+前端面试题大合集】

PHP+前端面试题大合集

PHP面试题

1、为什么SQL语句不要过多的join?

性能问题:每个join操作都需要对两个或多个表进行连接操作,这个操作需要消耗大量的计算资源和时间,如果join操作过多,会导致SQL的执行效率降低,从而影响整个系统的性能。
可读性和维护性问题:join操作会使SQL语句变得复杂,难以理解和维护。

2、PHP的垃圾回收机制?

PHP可以自动进行内存管理,清除掉不需要的对象。
PHP使用了引用计数机制。每个对象都内含一个引用计数器,每个指针指向连接到一个对象 计数器加一。
当指针指向离开或者被设为null,计数器减一。
当某个对象的引用计数器为零时,PHP就会释放其占用的空间。

3、面向对象七大原则?

单一职责原则:一个类应该只有一个职责。
开放封闭原则:在不修改源码的情况下,可以对其扩展,不影响原有功能。
里式替换原则:子类可以扩展父类,而不是覆盖父类或改变父类原有功能。
依赖倒置原则:依赖于抽象。
接口隔离原则:不要把功能写在一个接口中,不要依赖那些用不到的接口。
迪米特原则:降低类与类之间的耦合,没关系的类不要扯在一起。
合成/聚合复用原则:尽量使用trait和use,少使用extends。

4、PHP解决内存溢出?

增加PHP可用内存大小。
及时销毁大数组或变量。
根据业务规则,尽可能的少用静态变量。
数据库操作完及时关闭。

5、include和require的区别是什么?

如果一个流程中加入require,无论条件成立与否都会先执行。
include有返回值,require没有(require速度比include快)。
require报错会终止程序执行,include报错会继续执行下去。

6、微信实际支付成功,但回调失败如何处理?

临时页面处理:在返回页增加“支付成功”与“遇到问题,联系客服”按钮选项。这两个按钮都重新调取微信获取支付结果的接口,成功或失败都跳转到中间页。
定时处理:如果没有临时页,则根据业务情况,设置合适的回调周期,周期性访问“获取微信支付结果的接口”,将支付结果更新至数据库。

7、MySQL中int(10)和char(10)和varchar(10)的区别?

int(10)中的10表示的是显示数据的长度。
char(10)和varchar(10)表示的是存储数据的大小。

8、什么是临时表?

MySQL在执行SQL语句时会临时创建一些存储中间结果集的表,这种表被称为临时表。
临时表只对当前连接可见,在连接关闭后,临时表会被删除并释放空间。
下面几种情况会使用到临时表:
form中的子查询。
distinct查询并加上order by。
order by和group by的子句不一样时。
使用union查询时。

9、大表数据查询如何优化?

索引优化。
SQL语句优化。
水平拆分。
垂直拆分。
建立中间表。
使用缓存。
固定长度的表访问起来更快。
列内容越少访问越快。

10、字段为什么要设置为not null?

null值会影响一些函数的统计,如count遇到null值,这条记录就不会统计在内。
使用not in子查询时,有null值的情况下返回的结果都是空值。
MySQL在进行比较时,null会参与字段的比较。因为null是一种比较特殊的数据类型,数据库要做特殊处理,增加了数据库处理数据的复杂性。

11、如何优化查询过程中的数据访问?

正确使用索引,尽量做到索引覆盖。
数据分页处理。
只返回需要的字段。
合理使用排序。
减少比较的操作。

12、如何优化where子句?

不要在where子句中使用不等于判断,这样会导致放弃索引直接进行全表扫描。
不要在where子句中使用空值判断,字段尽量设置为not null。
在where和order by涉及到的列建立索引。
尽量减少使用in或者not in,会进行全表扫描。
避免在where子句中,对字段使用表达式或者函数操作,会导致放弃索引使用全表扫描。

13、Redis使用场景?

保存字符串、计数器、功能开关、队列、排行、关注点赞。

14、浏览器访问某个网址的详细过程?

1、用户访问域名。
2、域名DNS解析。
3、请求到对应IP服务器和端口。
4、nginx监听到对应端口的请求。
5、nginx对url进行location匹配。
6、nginx将请求转发给php。

15、如何解决并发问题?

1、根据需求及模块功能拆分成多个子系统。
2、应用集群、负载均衡。
3、设置文件存储服务器、图片存储服务器、专用搜索服务器。
4、限流方式:验证码、IP黑名单、nginx控制并发连接数。
5、Redis消息队列。
6、MySQL优化,主从复制、读写分离。

16、简单秒杀系统并发考虑?

1、前端秒杀页面静态化。
2、前端控制提交频率,按钮设置为灰色。
3、nginx控制IP限流。
4、后端用户限流,对用户uid计数。
5、Redis预先将商品入队列,请求时,控制串行处理。
6、防止直接通过链接访问秒杀页面,秒杀链接通过父级页面点击获取唯一标识,没有携带标识的请求返回没抢到。

17、怎么保证促销商品不会超卖?

方案一:在每次下订单前判断促销商品的数量够不够,不够不允许下单。更改库存数量时加上一个条件,只更改商品库存大于0的商品。我们使用ab进行压力测试,当并发超过500,访问量超过2000时还是会出现超卖现象。
方案二:使用MySQL的事务加排它锁来解决,首先选择数据库的存储引擎为innoDB。但当我们进行高并发测试时,对数据库的性能影响很大。
最终我们使用Redis队列来实现,将要促销的商品数量以队列的方式存入redis。每当用户抢到一件促销商品就从队列中删除一个数据,确保商品不会超卖。

18、redis消息队列先进先出需要注意什么?

在使用一个list来实现队列操作时,所有任务统一都是先进先出,我们需要一个优先级的概念,这样就可以优先处理高级别的任务了。
1、队列正常操作是左进右出(lpush,rpop),在遇到高级别任务时,可以直接插队放入队列尾部(rpush),这样从队列尾部获取的任务就是高优先级任务了。
备注:(brpop是rpop的阻塞模式) 语法结构:BRPOP key [key …] timeout 弹出列表尾部第一个元素并返回存储它的key
2、使用两个队列,一个普通队列,一个高级队列。针对任务的级别放入不同的队列,redis的brpop命令可以按顺序从多个队列中取值,brpop会按照给出key的顺序来找到第一个非空list,再从尾部弹出一个元素。

19、数据库索引的目的是什么?

快速访问数据表中特定信息,提高检索速度。
创建唯一索引,保证数据表中每一行数据的唯一性。
加速表与表之间的连接。
使用分组和排序子句进行查询时,可以减少分组和排序的时间。

20、索引对数据库系统的负面影响是什么?

创建和维护索引需要耗费时间,这个时间随着数据量的增加而增加。
索引需要占用物理空间,不光是表需要占用数据空间,每个索引也需要占用物理空间。
当对表进行增、删、改的时候,索引也要动态维护,这样就降低了数据的维护速度。

21、post是两次请求的原因?

第一条为options请求,第二条才是我们预想的请求。
在正式请求之前,先进行一次预检请求。看服务器返回一些信息,浏览器拿到后看后台是否允许进行访问。
只要是带有自定义header的跨域请求,就会发生options请求。只需要避免跨域或者不在header头部加自定义内容。

22、PHP常用函数?

ceil(9.99); 浮点数进一取整
floor(9.99); 浮点数舍去小数部分
round(3.1415, 2); 保留2位小数
intval(); 获取变量的整数值
isset(); 检测变量是否设置
empty(); 检测变量是否为空

strlen(); 获取字符串的长度
strtotime(); 将文本日期时间描述解析为Unix时间戳
str_repeat(‘.’, 9); 重复使用指定字符串
str_split(‘hello’); 把字符串分割到数组中
explode(); 使用一个字符串为标志分割另一个字符串
implode(); 将数组值用预定字符连接成字符串
substr(); 截取字符串
strpos(); 查找字符串中某个子串的位置
str_replace(); 替换字符串中的内容
json_decode(); 对json格式的字符串进行解码
json_encode(); 对变量进行json编码

array_merge(); 两个或多个数组合并为一个数组
in_array(‘hello’, data); 数组中搜索给定的值 区分大小写
array_key_exists(); 判断数组中是否存在指定的key
list($a, $b, $c); 用数组中的元素为一组变量赋值
array_shift(); 移出数组中的第一个元素
array_unshift(); 在数组开头插入一个或多个元素
array_push(); 向数组最后压入一个或多个元素
array_pop(); 取出数组中的最后一个元素
count(); 计算数组个数
array_keys(); 返回数组所有的键,组成一个数组
array_values(); 返回数组所有的值,组成一个数组
uasort(); 使用自定义的比较函数对数组进行排序
arsort(); 数组按值从高到低排序

23、索引有哪几种类型?

主键索引:数据列不允许重复,不允许为null,一个表只能有一个主键。
唯一索引:数据列不允许重复。
普通索引:基本的索引类型,可以重复也可以为null。
全文索引:是目前搜索引擎使用的一种关键技术。

24、mysql哪些字段适合建立索引

表的主键、外键必须有索引;
数据量超过300的表应该有索引;
经常与其他表进行连接的表,在连接字段上应该建立索引;
经常出现在where子句中的字段,特别是大表的字段,应该建立索引;
索引应该健在小字段上,对于大的文本字段甚至超长字段,不要建索引;
复合索引的建立需要进行仔细分析,尽量考虑用单字段索引代替:1.判断几个字段是否经常以and方式出现在where子句中?单字段查询是否极少使用?如果是,可以使用复合索引;2.如果复合索引中包含的字段经常单独出现在where子句中,则分解为多个单字段索引;
频繁进行数据操作的表,不要建立太多的索引;

25、rabbitMQ消息队列的应用场景?

消息队列可以作为消息中间件使用,例如PHP和Python通过rabbitMQ做数据的互联。
可以当做多进程异步操作来使用,将一个任务分配给多个服务同时执行。比如下单成功后的邮件通知和短信通知。
防止服务器一下处理过多请求,消费者读取队列中数据是一条一条读取,服务器不会超负荷。

26、Redis数据类型有哪些?

string 字符串、list 链表、hash 哈希表、set 集合、zset 有序集合

27、Linux常用命令

du -sh /etc/ 查看目录所占用磁盘空间情况
df -h 查看磁盘剩余空间情况
find / -name [文件名] 根据名字查找文件
ps -ef | grep nginx 查看进程,通常与管道操作连用
kill [PID] 杀掉进程,后面跟进程id
top 查看资源占用情况,一般用来排查高占用的异常进程

28、laravel生命周期

所有请求的入口是index.php文件,从该文件中加载composer。
实例化app容器,绑定http、console内核。
在http内核中,将中间件注册到路由。
路由将请求转发到绑定的控制器。
通过路由中间件返回一个响应。
调用send方法将响应内容发送到用户。

前端面试题

1、移动端适配方案

1、rem
2、百分比
3、vw/vh,vmin/vmax
4、flex
5、栅格布局

2、常用的vue2生命周期

created:实例已经创建完成,数据和方法都已存在。常用于发送请求获取数据,页面进入的方法需要立即执行。
mounted:dom已经挂在完成,可以操作真实dom。
updated:数据和视图都变了。
destoryed:组件销毁。常用于清除定时器等行为。

3、v-if和v-show

v-if:移除或添加dom元素。在dom首次判断是否显示还是隐藏,或者组件需要重新触发生命周期时使用。
v-show:通过css的display样式来控制显示隐藏。频繁的显示和隐藏时使用。

4、如何理解单向数据流

数据是单向流动,数据可以从父组件流向子组件,父组件的数据发生变化,会自动同步子组件,反之不允许。

5、为什么v-if和v-for不建议同时使用

v-for比v-if优先级高,每次都需要遍历整个数组,影响性能。
要避免出现这种情况,可以在外层嵌套template,在这一层进行v-if判断,然后在内部进行v-for循环。
如果条件出现在循环内部,可以通过计算属性computed提前过滤掉那些不需要显示的部分。

6、vue中css的scoped作用和原理

作用:实现组件的私有化,表示当前style属性只属于当前模块。
原理:scoped会在dom结构以及css样式加上唯一性标记,也就是css的属性选择器,以此来完成样式私有化。

7、虚拟dom和diff算法

虚拟dom本质就是一个js对象,用来描述真实的dom。
初始化渲染时候,会根据数据和模板生成虚拟dom树,当数据发生变化时,会根据新数据生成新的dom树,将两份虚拟dom树使用diff算法进行对比。
diff算法使用双指针算法,遍历旧的虚拟dom有两个指针,指向开始位置和结束位置。同理新的虚拟dom也有这两个指针,对比完成后前面指针会往后推,后面的往前推。

8、$nextTick

由于在vue中数据驱动视图是异步的,所以就会导致数据发生变化视图没有同步更新。想要获取到最新的视图就可以借助$nextTick。

9、$route和 $router作用

$route:获取当前路由信息。
$router:全局路由实例,可以使用路由方法进行前后跳转等。

10、项目优化

1、移除console.log。
2、webpack的代码分割功能来实现路由懒加载,把不同路由对应的组件分割成不同的代码块,当路由匹配的时候才会加载响应资源。
3、splitChunks提取公共资源,某一个文件被多次引入将他提取出来。
4、image-webpack-loader实现图片资源压缩。
5、使用SSR服务端渲染,首屏服务端直接返回。
6、UI框架按需加载。
7、减少data。
8、图片懒加载。
9、异步加载,导出组件。
10、清除事件定时器。

11、实现token无感刷新

企业上常用的解决方案是token + refresh-token(刷新令牌)来实现无感刷新。登录验证用户凭证时生成两个令牌,一个用于访问资源,一个用于刷新访问令牌,当token过期时,使用刷新令牌来获取新的访问令牌。

12、实现大文件上传

文件切片:使用文件对象原型上的slice方法,从原始文件中提取指定的部分内容,返回一个新的Blob对象。可以通过固定切片大小或者是固定切片数量来对文件进行切割,利用Promise.allSettled批量发送请求,来并行上传所有文件切片。每个切片文件需要一个按顺序的标记位,文件需要按顺序合并。要给切片提供一个和文件内容相关的hash值,用于标记每个文件切片,确保切片与原始文件内容相关。
断点续传:因为标记的hash值是使用文件内容编译的,后端可以记住已经上传过的切片,自行过滤就行了。

13、axios取消请求

axios上有一个CancelToken构造函数,通过该构造函数创建一个实例,将该实例绑定给需要取消请求接口的cancelToken属性上,当要取消请求时调用CancelToken内部返回的回调就可以实现取消接口请求。

14、websocket

websocket是一种网络通信协议,提供了在单个TCP连接上进行全双工通讯的功能。它提供了实时双向通信,非常适合需要实时数据更新的应用。与HTTP相比,websocket在建立连接后可以随时发送消息,减少了每次需要发送HTTP头的开销。我们项目中使用 socket.io-client 来实现客户端代码,它是基于 websocket 的库。

15、地址栏输入url过程

1、检查url是否合法。
2、域名DNS解析。
3、三次握手建立TCP连接:第一次客户端发送网络包,服务端收到了。服务端确定了客户端发送能力和服务端的接收能力是正常的。第二次服务端发包,客户端收到了,客户端确定了服务端接收发送能力和自己的接收发送能力是正常的。第三次客户端发包,服务端收到了。服务端就能确定了客户端和自己的发送接收能力是正常的。
4、发起http请求
5、响应请求
6、页面渲染:html生成dom树,style生成css规则树。
7、tcp终止一个连接,四次挥手:第一次客户端发送一个FIN报文,此时客户端停止发送数据,等待服务端确认。第二次服务端同意,响应服务端收到的消息。此时处于半链接,有可能有数据没发送完,继续发送未发送完的数据。第三次服务端发送完成,服务端要彻底断开了,给客户端发消息并处于等待状态。客户端收到FIN之后,第四次发送一个应答,服务器只要收到客户端的确认就进入关闭状态。

16、GET和POST请求的区别

1、get请求一般用来请求获取数据。post请求一般作为发送数据到后台,传递数据,创建数据。
2、get请求传递的参数显示在地址栏,安全性低,且参数的长度也有限制(2048字符)。post请求则是将传递的参数放在request body中,安全性更高,且参数没有长度限制。
3、get请求刷新浏览器或者回退没有影响,post请求则会重新请求一遍。
4、get请求可以被缓存,也会保留在浏览器的历史记录中。post请求不会被缓存。
5、get请求通常是通过url地址请求,post常见的则是form表单请求。
6、get产生一个tcp数据包,post产生两个tcp数据包。

17、JavaScript中的数据类型和存储上的区别

基本数据类型:Number、String、Boolean、Undefined、null、symbol、bigInt
复杂数据类型:Object、Array、Function
简单类型的值存放在栈中,在栈中存放的是对应的值。引用类型对应的值存储在堆中,在栈中存放的是指向堆内存的地址。所以当简单类型赋值时,是生成相同的值,两个值对应不同的地址。复杂类型赋值,是将保存对象的内存地址赋值给另一个变量,也就是两个变量指向堆内存的同一个地址。

18、深浅拷贝

浅拷贝:指拷贝复制目标数据,生成一个新数据。如果是基本数据类型,则直接拷贝目标数据的值。如果是引用数据类型,第一层数据有引用类型的值则直接拷贝地址。由于拷贝的是地址,指向的是同一个对象,所以数据修改会相互影响。
深拷贝:会拷贝所有的属性,如果这些属性是对象,也会对这些对象进行深拷贝。对于深拷贝后的对象,即使原对象的属性值发生变化,拷贝后的也不会受到影响。

19、讲一下Promise使用

简单说它是一个容器,通常用于表示一个异步操作的最终完成和结果。可以配合async和await将异步代码变为类似同步的,new Promise()传入的函数是会立即执行的是同步的,new Promise().then()是异步的。

20、如何中断forEach循环

使用return、break、continue的方式都不能终止forEach循环,可以使用throw new Error终止循环。

21、js本地存储的方式

cookie:为了辨别用户身份存储在用户本地终端上的数据,解决http无状态导致的问题。
localStorage:持久化本地存储,除非主动删除数据,否则数据永远不会过期。
sessionStorage:与localStorage使用方法一样,但是页面关闭了数据也会删除。

22、聊聊异步

可以使用Promise发起异步。如果是同步任务,主线程自己来执行。如果是异步任务,交给浏览器执行。每个异步任务执行完后,会将回调放进任务队列,等主线程任务全部执行完后,再去取任务队列中的任务。

23、为什么不建议用index索引作为key

使用index作为key和没写基本没区别,因为不管数组的顺序怎么颠倒,index都是0,1,2这样排列,导致vue会复用错误的旧子节点,做很多无意义的额外工作。