面试题整理 4
总结整理了某公司面试中值得记录的笔试和问到的问题和答案。
目录
PHP传值和传引用区别?什么情况下用传值?什么情况下用传引用?
传值
传引用
区别
选择传值还是传引用时
简述PHP的垃圾回收机制
二维数组排序
什么是CSRF攻击?XSS攻击?如何防范?
CSRF
防范主要方法
XSS
防范主要方法
主键、外键和索引区别
__autoload()方法的工作原理?与spl_autoload_register()的区别?
用什么方法检查PHP脚本执行效率(通常是脚本执行时间)和数据库SQL的效率(通常是数据库的Query时间),并定位和分析脚本执行和数据库查询的瓶颈所在?
PHP脚本执行时间
数据库SQL查询效率
Mysql什么是事务及其特性?事务的隔离级别分别是?
事务及特性
隔离级别
Mysql数据库做发布系统存储,一天五万条以上增量,预计运维三年,怎么优化?
Nginx访问日志,怎么统计IP访问量(独立ip访问数量)前十的ip。命令怎么写
什么是API幂等性?怎么解决幂等问题?
概念
实现API幂等性的主要方法包括:
对于大流量网站,采用什么样的方法来解决访问量问题
两个变量在不设置第三个变量时怎么互换值
算术运算
异或运算
git合并另一分支的一部分提交
100万用户每日签到功能如何实现
十个座位被六七百学生预约如何不超约和重复约
十万用户 下载全年某搜索结果数据 如何实现
如何导出excel文件
laravel orm都使用了哪些设计模式具体示例
工厂方法模式
抽象工厂模式
原型模式
建造者模式
单例模式
什么mysql回表?如何避免回表?
避免回表优化方式:
PHP传值和传引用区别?什么情况下用传值?什么情况下用传引用?
传值
函数范围内对值的任何改变在函数外部都会被忽略
传引用
函数范围内对值的任何改变在函数外部也能反映出这些修改
区别
按值传递时,php必须复制值。特别是对于大型的字符串和对象来说,这将是代价很大的操作按引用传递则不需要复制值,对于性能提高很有好处。
传值只是把某一个变量的值传给另一个变量,而引用则说明两者指向同一个地方
选择传值还是传引用时
传值适用于不需要修改原始变量的情况,或者原始变量是大型数组或对象时,以避免内存消耗。
传值可以确保函数或方法的独立性,不会对其他代码产生意外的副作用。
传引用适用于需要修改原始变量的情况,以避免创建副本和消耗额外的内存。 通常情况下,当函数或方法需要修改输入参数的值时,更倾向于使用传引用。但是,应该谨慎使用传引用,因为它可能导致代码难以理解和维护,以及不受控制的副作用。
简述PHP的垃圾回收机制
PHP的垃圾回收机制是自动的,它通过内置的垃圾回收器(Garbage Collector)来实现。当一个PHP对象不再被引用时,它就成为垃圾。垃圾回收器会定期扫描内存中的所有对象,将没有引用的对象标记为垃圾,并释放它们占用的内存空间,以便其他对象可以使用这些空间。
PHP的垃圾回收机制使用了引用计数(reference counting)的算法来跟踪对象的引用情况。每个对象都有一个引用计数器,它记录着对象当前被引用的次数。当一个对象被赋给一个变量时,它的引用计数器会增加1;当一个变量不再引用该对象时,它的引用计数器会减少1。当引用计数器降为0时,这个对象就成为垃圾,垃圾回收器就会释放它所占用的内存。
PHP的垃圾回收机制是自动的,程序员无需手动管理内存。但是,如果程序中存在循环引用的情况,垃圾回收器就无法释放这些对象。为了避免这种情况的发生,PHP提供了一种手动解除引用的方法,即将对象赋值为null,这样就可以让对象的引用计数器降为0,从而被垃圾回收器释放。
二维数组排序
有一个二维数组,子数组中元素有排序和距离两个元素,写一个方法先按照排序由大到小,如果排序相同在按照距离由近到远
array_multisort()函数是一个非常强大的排序函数,可以按照多个条件对二维数组进行排序。如果想按照多个字段进行排序,可以使用array_multisort()函数。例如,我们要首先按照age字段排序,如果age相同,则按照id排序。
示例如下:
$arr = [
['sort' => 10, 'distance' => 2],
['sort' => 9, 'distance' => 8],
['sort' => 7, 'distance' => 6],
['sort' => 2, 'distance' => 3],
['sort' => 1, 'distance' => 1],
['sort' => 9, 'distance' => 2],
['sort' => 1, 'distance' => 2],
];
$sorts = $distances = [];
foreach ($arr as $v) {
$sorts[] = $v['sort'];
$distances[] = $v['distance'];
}
array_multisort($sorts, SORT_DESC, $distances, SORT_ASC, $arr);
print_r($arr);
什么是CSRF攻击?XSS攻击?如何防范?
CSRF
Cross-Site Request Forgery,即跨站请求伪造,是一种利用用户的登录状态,以用户身份进行非法的操作。攻击者通过盗用用户的身份,在用户不知情的情况下完成一些危害性的操作,比如删除账号,发邮件等。攻击者通常会诱骗用户点击带有攻击性的链接,或者注入恶意代码到被攻击网站中,等待用户点击触发。
防范主要方法
1. 验证请求来源:在服务端验证请求是否来自合法的源,比如检查Referer、Origin头部,验证CSRF Token等。
2. 使用验证码: 验证码可以有效减少CSRF攻击,因为攻击者并不能获取验证码的值。
XSS
Cross-Site Scripting,即跨站脚本攻击,是指攻击者在网页中注入可执行的代码,当用户浏览该网页时,注入的代码会被执行,从而达到盗取用户信息、窃取Cookie、篡改网页等恶意目的的攻击方式。攻击者通常会在提交或传输数据时,利用未经过滤的HTML或JavaScript注入攻击代码。
防范主要方法
1. 对用户输入的数据进行过滤和转义,不信任任何来自用户的数据。
2. 设置HTTP头中的安全策略,具体包括X-XSS-Protection、Content-Security-Policy(CSP)等。
3. 使用最新的浏览器,并开启浏览器的反XSS策略,例如开启Chrome的XssAuditor。
4. 避免使用eval、innerHTML、document.write等可执行脚本的API,选择使用更为安全的替代方案。
主键、外键和索引区别
索引是一种增加查询效率的数据结构,它是在数据库表上建立的。索引可以快速定位表中的数据行,提高查询速度和排序速度。
主键是索引的一种,一个表只能定义一个主键,且主键不能为NULL。它用来保证表中记录的唯一性,也可以用来快速查找和定位记录。
外键是一种参照其他表的键,它限制了一个表中某个字段的取值必须是另一个表中某一字段的取值。外键可以用来建立两个表之间的关联,从而实现数据的一致性。
__autoload()方法的工作原理?与spl_autoload_register()的区别?
__autoload() 函数是用户定义的函数,用于动态加载 PHP 类文件,当脚本尝试使用一个未被定义的类时,PHP 解释器将会寻找 __autoload() 函数,并执行该函数,将类名作为一个参数传入。
与spl_autoload_register()的区别是只能定义一次,不能重复定义。
用什么方法检查PHP脚本执行效率(通常是脚本执行时间)和数据库SQL的效率(通常是数据库的Query时间),并定位和分析脚本执行和数据库查询的瓶颈所在?
PHP脚本执行时间
使用 microtime() 函数,在脚本开始和结束处记录时间,然后计算差值。
示例如下:
$start_time = microtime(true);
// PHP代码
$end_time = microtime(true);
$execution_time = $end_time - $start_time;
echo "执行时间: " . $execution_time . " 秒";
数据库SQL查询效率
使用 mysqli_query() 的 get_result() 方法和 mysqli_get_profiling_info() 函数。
示例如下:
$db = new mysqli('localhost', 'username', 'password', 'database');
$db->set_charset('utf8');
// 启用性能分析
$db->profiling = 1;
// 执行一个查询
$query = "SELECT * FROM user";
$stmt = $db->prepare($query);
$stmt->execute();
$result = $stmt->get_result();
// 获取所有查询的性能信息
$profiling_info = $db->get_profiling_info();
foreach ($profiling_info as $info) {
if ($info['query'] == $query) {
echo "查询耗时: " . $info['duration'] . " 秒";
break;
}
}
Mysql什么是事务及其特性?事务的隔离级别分别是?
事务及特性
事务:是一系列的数据库操作,是数据库应用的基本逻辑单位。
特性:
(1)原子性:即不可分割性,事务要么全部被执行,要么就全部不被执行。
(2)一致性或可串性。事务的执行使得数据库从一种正确状态转换成另一种正确状态
(3)隔离性。在事务正确提交之前,不允许把该事务对数据的任何改变提供给任何其他事务
(4) 持久性。事务正确提交后,其结果将永久保存在数据库中,即使在事务提交后有了其他故障,事务的处理结果也会得到保存。
简单理解:在事务里的操作,要么全部成功,要么全部失败。
隔离级别
在 MySQL中事务的隔离级别有以下 4 种:
读未提交(READ UNCOMMITTED)
读已提交(READ COMMITTED)
可重复读(REPEATABLE READ)
序列化(SERIALIZABLE)
MySQL 默认的事务隔离级别是可重复读,这4种隔离级别的说明如下。
1.READ UNCOMMITTED
读未提交,也叫未提交读,该隔离级别的事务可以看到其他事务中未提交的数据。该隔离级别因为可以读取到其他事务中未提交的数据,而未提交的数据可能会发生回滚,因此把该级别读取到的数据称之为脏数据,把这个问题称之为脏读。
2.READ COMMITTED
读已提交,也叫提交读,该隔离级别的事务能读取到已经提交事务的数据,因此它不会有脏读问题。但由于在事务的执行中可以读取到其他事务提交的结果,所以在不同时间的相同 SQL查询中,可能会得到不同的结果,这种现象叫做不可重复读。
3.REPEATABLE READ
可重复读,是MySQL的默认事务隔离级别,它能确保同一事务多次查询的结果一致。但也会有新的问题,比如此级别的事务正在执行时,另一个事务成功的插入了某条数据,但因为它每次查询的结果都是一样的,所以会导致查询不到这条数据,自己重复插入时又失败(因为唯一约束的原因)。明明在事务中查询不到这条信息,但就是插入不进去,这就叫幻读 (Phantom Read)。
4.SERIALIZABLE
序列化,事务最高隔离级别,它会强制事务排序,使之不会发生冲突,从而解决了脏读、不可重复读和幻读问题,但因为执行效率低,所以真正使用的场景并不多。
Mysql数据库做发布系统存储,一天五万条以上增量,预计运维三年,怎么优化?
1、设计良好的数据库结构,允许部分数据冗余,尽量避免 join 查询,提高效率。
2、选择合适的表字段数据类型和存储引擎,适当的添加索引。
3、MySQL 库主从读写分离。
4、找规律分表,减少单表中的数据量提高查询速度。
5、添加缓存机制,比如 memcached,redis 等。
6、不经常改动的页面,生成静态页面。
7、书写高效率的 SQL。比如 SELECT * FROM TABEL 为 SELECT field_1,field_2 FROM TABLE.
Nginx访问日志,怎么统计IP访问量(独立ip访问数量)前十的ip。命令怎么写
awk '{print $1}' /path/to/nginx/access.log | sort | uniq -c | sort -nr | head -10
解释:
cat /var/log/nginx/access.log:输出日志文件内容。
awk '{print $1}':使用awk打印每行的第一个字段,通常是IP地址。
sort:对所有IP地址进行排序,以便uniq可以统计重复项。
uniq -c:计算每个唯一IP出现的次数。
sort -nr:以数值形式逆序排序结果。
请根据实际Nginx日志格式调整awk命令中的$1,以指向包含IP地址的正确字段。
什么是API幂等性?怎么解决幂等问题?
概念
API幂等性指的是对于同一个API请求,无论执行一次还是多次,其结果和效果都是相同的。简单来说,就是多次调用对系统的产生的影响是一样的,即对资源的作用是一样的。幂等性强调的是外界通过接口对系统内部的影响,只要一次或多次调用对某一个资源应该具有同样的副作用就行。注意,这里指对资源造成的副作用必须是一样的,但是返回值允许不同。
实现API幂等性的主要方法包括:
唯一索引:通过为数据库表设置唯一索引,避免插入重复数据,当插入重复数据时数据库会抛出异常,保证了数据的唯一性。
乐观锁:为数据字段增加一个版本号(version字段),当数据需要更新时,首先检查版本号是否一致。如果不一致,说明有其他请求已经更新了数据,提示更新失败。
悲观锁:在获取数据时进行加锁,防止多个请求同时更新同一数据。
分布式锁:在分布式环境下,通过Redis或Zookeeper等实现分布式锁,锁定全局唯一资源,使请求串行化,防止重复执行。
Token机制:为每一次操作生成一个唯一性的凭证(token),token在操作的每一个阶段只有一次执行权,一旦执行成功则保存执行结果。对重复的请求,返回同一个结果。
这些方法可以根据具体的业务场景和需求选择合适的方式来实现API的幂等性,以确保系统的稳定性和数据的准确性
对于大流量网站,采用什么样的方法来解决访问量问题
确认服务器硬件是否足够支持当前的流量:首先需要确保服务器的硬件配置能够支持当前的高流量负载。这包括足够的CPU、内存、存储空间以及网络带宽等12。
优化数据库访问:通过优化数据库查询、使用缓存技术(如Memcached或Redis)来减少对数据库的直接访问,从而提高响应速度和系统效率12。
控制大文件的下载:限制大文件的下载,尤其是对于非SCSI硬盘,大量文件下载会消耗CPU资源,影响网站响应能力。如果需要提供大文件下载,可以考虑使用专门的文件服务器来分担主服务器的负载25。
使用静态页和缓存:尽量使用静态页面,或者对动态页面进行缓存,以减少对服务器的请求次数,提高访问速度14。
负载均衡:通过负载均衡技术,将请求分发到多个服务器上,以增加系统的处理能力和吞吐量。这可以通过专门的负载均衡硬件(如F5)或软件实现34。
使用不同主机分流主要流量:将静态内容(如图片、CSS、JavaScript文件等)放在不同的主机上,提供镜像服务,以减轻主服务器的负载25。
禁止外部的盗链:防止其他网站盗链你的资源,这可以通过技术手段(如Referer检查)来实现,从而减少不必要的流量消耗25。
使用流量分析统计软件:通过使用流量分析统计软件(如Google Analytics),可以实时监控网站的流量情况,发现并解决潜在的流量问题5。
综上所述,解决大流量网站的访问量问题需要从硬件升级、技术优化、流量管理等多个方面进行综合考虑和实施。
两个变量在不设置第三个变量时怎么互换值
算术运算
通过加法和减法运算可以实现两个变量的值互换。首先,将两个变量的值相加,然后将结果赋值给其中一个变量。接着,将原来的第一个变量值减去刚刚赋值的变量值,完成互换。具体步骤如下:
将变量a的值加上变量b的值,然后将结果赋值给a。
将原来的a的值减去刚刚赋值的变量值,然后将结果赋值给b。
例如,如果a的初始值为2,b的初始值为1,那么通过上述步骤,a和b的值将会互换,最终a的值为1,b的值为2。
异或运算
异或运算(XOR)也可以用来交换两个变量的值。异或运算的特点是,如果两个输入值相同,则输出为0;如果不同,则输出为1。利用这个特性,可以将两个变量的值进行交换。具体步骤如下:
将变量a与变量b进行异或运算,然后将结果赋值给a。
再次将变量a与上一步的结果进行异或运算,然后将结果赋值给b。
最后,将变量a与上一步的结果再次进行异或运算,赋值给a。
通过这种方式,可以确保两个变量的值被交换,而不需要使用第三个变量。
git合并另一分支的一部分提交
# 切换到目标分支
git checkout main
# 查找想要合并的提交的哈希值
git log --oneline
# 假设我们想要合并的提交哈希值是123abc
git cherry-pick 123abc
# 如果有冲突,解决它们,然后继续
git add .
git cherry-pick --continue
# 或者,如果你想取消cherry-pick
git cherry-pick --abort
100万用户每日签到功能如何实现
使用redis 二进制实现用0或者1表示当月用户是否签到。
具体介绍:
Redis实现每日签到(大数据量)_php redis实现每日签到(大数据量)-CSDN博客
十个座位被六七百学生预约如何不超约和重复约
今天简单的用redis的队列来解决超卖问题。因为redis有list类型,list类型其实就是一个双向链表。通过push,pop操作从链表的头部或者尾部添加删除元素。这使得list既可以用作栈,也可以用作队列。先进先出 一端进 一端出这就是队列。
这里用redis来解决并发问题:
首先在队列中增加一个product_num的key,加入10个座位的内存数据。
将库存循环lpush进一个redis值product_num里去,
然后在下单的时候依次rpop出来。
下一个单取出来一个,然后等product_num的值为0时,停止下单。
下单时判断用户预约的座位号和是否预约重复,
如果重复直接提示用户重复了,请重新预约。
然后redis库存再增加回去。
如果座位没有预约,则执行预约并提示用户预约成功。
十万用户 下载全年某搜索结果数据 如何实现
异步实现,当用户点击下载时提示数据量过大,需要一定时间请耐心等待,然后到下载中心去查看下载状态。异步处理下载完成后,把文件下载状态修改并返回文件地址。
如何导出excel文件
在PHP中导出Excel文件,可以使用PhpSpreadsheet库,这是一个非常流行的库,用于在PHP中读写电子表格文件。
laravel orm都使用了哪些设计模式具体示例
工厂方法模式
Laravel的Eloquent ORM模型工厂和表单请求工厂是工厂方法模式的体现。这种模式提供了一个创建对象的接口,而不指定其具体类,从而实现了对象的创建与使用分离,提高了系统的可扩展性和灵活性。
抽象工厂模式
在Laravel中,配置文件、服务提供者、门面(Facades)、多环境配置、依赖注入容器等体现了抽象工厂模式的应用。这种模式提供了一种创建相关或依赖对象的接口,而无需指定它们的具体类,从而实现了对象的创建与使用分离。
原型模式
Laravel中的配置对象复制、请求和响应的快速复制、会话管理、数据模型的快速复制、缓存数据的复制等操作体现了原型模式的运用。这种模式通过复制现有对象来创建新对象,避免了直接操作对象本身,提高了系统的可维护性和可扩展性。
建造者模式
Laravel中的表单和HTML的构建、查询构建器、邮件消息构建、视图组件和插槽、集合操作、表单请求验证等操作都是建造者模式的体现。这种模式通过一系列步骤来构建复杂对象,允许用户在不了解对象创建细节的情况下对其进行定制和组装。
单例模式
Laravel中的服务容器、门面(Facades)、配置和环境、日志、路由服务、会话管理、缓存管理等都是单例模式的实例。单例模式确保了一个类只有一个实例,提供了全局访问点,从而简化了全局状态的管理和维护。
什么mysql回表?如何避免回表?
MySQL中的"回表"是指在使用索引查询数据时,如果需要查询的数据不在索引节点上,那么就需要通过索引上的地址(如行指针或者ROWID)去查询实际的数据行。这个过程称为"回表"。
回表通常发生在索引的"覆盖"情况下,即查询的列都包含在创建索引时指定的列中。如果查询的列没有完全包含在索引中,那么即使是索引扫描,MySQL也需要回表查询实际的数据行。
举个例子,假设有一个表users,包含列(id, name, age, address),并且有一个索引(name)。
如果执行查询SELECT name FROM users WHERE name = 'Alice';,因为name列已经在索引中,这个查询不需要回表。
但如果执行查询SELECT name, age FROM users WHERE name = 'Alice',即使age不在索引(name)中,由于索引覆盖了查询的列,MySQL仍然可以从索引中获取所需数据,不需要回表。
如果查询SELECT name FROM users WHERE age > 30,即使name在索引中,由于查询条件涉及到age列,age不在索引(name)中,MySQL也需要回表查询实际的数据行。
避免回表优化方式:
为了减少回表,可以考虑以下方法:
优化查询,使用索引覆盖更多的列。
创建多列索引,如(name, age),这样就可以覆盖更多的查询列。
使用覆盖索引,即只使用索引进行查询,不查询实际的数据行,而是返回索引的列即可。