PHP面试题(二)

一、数组运算

$a=[0,1,2,3];
$b=[4,5,6,7,8];
$a += $b;

$a 等于多少?
答:[0,1,2,3,8]

二、语句include和require的区别是什么?重复包含同一个文件分别会有什么提示?

include:包含并执行指定文件,文件不存在时发出警告继续执行后续代码。
require:包含并执行指定文件,文件不存在时发出致命错误停止执行后续代码。

include 和 require:如果重复包含的文件中有重复定义的函数、类或常量,PHP会抛出致命错误(E_ERROR),例如“Cannot redeclare function_name()”。

在实际使用中,选择 include 还是 require 取决于文件的重要性。对于必须包含的文件(如配置文件),应使用 require;对于可选包含的文件(如模板文件),可以使用 include。为了避免重复包含问题,建议使用 include_once 或 require_once。

三、有两个数组[1,2,5,11,32,15,77]和[99,32,15,5,1,77]两个数组,写段程序找出它们共同都拥有的数

方法1、使用 array_intersect 函数找出两个数组中的共同元素
方法2、循环

四、写条语句从user 表随机调取 1 条数据?

select * from user order by rand() limit 1;
使用 RAND() 函数对结果集进行随机排序。

五、描述下Trait的继承优先级?

自身方法 > Trait 方法 > 父类方法

六、php缓存可以使用哪些软件,各自特点是什么?

多线程:memcache支持多线程,Redis支持单线程

持久化:Redis支持持久化,memcache不支持持久化

分布式:Redis做主从结构,memcache服务器需要通过hash一致化来支撑主从结构

七、如何排查和优化查询比较慢的sql语句?

  1. 通过explain 可以查看一条SQL使用哪些索引和有什么使用临时表
    关注以下字段:
    type:访问类型,如 ALL、index、range 等。
    key:使用的索引名称。
    rows:估计的行数。
    Extra:其他信息,如是否使用了临时表、文件排序等。

  2. 优化查询语句本身和添加索引

    • 仅选择需要的字段,避免使用 SELECT *。
    • 确保 WHERE 条件中使用了索引列。
    • 避免在索引列上使用函数或运算符,这会阻止索引的使用。
    • 根据查询的 WHERE 条件和连接条件添加索引。
    • 过多或不必要的索引会增加写操作的开销,影响性能。
  3. 对于不经常变化且查询频繁的数据,可以考虑使用缓存,如 Memcached、Redis 等。

  4. 使用MySQL 的慢查询日志

八、mysql数据库索引有哪些?什么情况下不适合建立索引?

  1. 主键索引(Primary Key)
    主键索引是唯一标识每条记录的索引,确保表中每行数据都有唯一的标识。
    一个表只能有一个主键索引,通常是在主键字段上创建的。
  2. 唯一索引(Unique Index)
    唯一索引确保索引列中的所有值都是唯一的,但允许存在空值(NULL)。
    一个表可以有多个唯一索引,可以用来确保列或组合列的唯一性。
  3. 普通索引(Normal Index)
    普通索引是最基本的索引类型,用于加快对列的查询速度。
    可以对表中的任意列创建普通索引。
  4. 全文索引(Full-Text Index)
    全文索引用于在文本数据中进行全文搜索,例如文章内容或文档。
    可以对 CHAR、VARCHAR 或 TEXT 类型的列创建全文索引。
  5. 组合索引(Composite Index)
    组合索引是包含多个列的索引,用于加快联合条件的查询。
    查询时可以利用索引覆盖多个查询条件。
  6. 空间索引(Spatial Index)
    空间索引用于优化空间数据类型的查询,例如地理位置信息。
    可以用于 GEOMETRY、POINT、LINESTRING 等空间数据类型的列。

对于经常用作 WHERE 子句中的查询条件、ORDER BY 进行排序、JOIN 操作中连接的列,通过索引可以加快连接操作的速度。
不适合建立索引的情况:

  • 低基数的列:基数(Cardinality)指的是列中不同值的数量。如果列中的值几乎全部相同,建立索引的效果会很小。

  • 频繁更新的列:对于频繁更新的列(特别是使用 UPDATE 和 DELETE 操作的列),索引可能会增加维护成本,并且在插入新记录时可能会影响性能。

  • 小表:对于行数很少的表,查询速度本身已经很快,额外的索引可能不会带来显著的性能提升,反而增加了存储和维护成本。

  • 不会用到的列:如果某列很少用作查询条件,或者几乎不会出现在 WHERE 子句中,建立索引可能没有意义。

  • 文本/图像类型的列:对于 TEXT、BLOB 等大字段类型,通常不适合建立索引,可以考虑使用全文索引或者其他技术来优化查询。

九、缓存穿透、缓存雪崩、缓存击穿的区别以及对应的解决方案?

  1. 缓存穿透(Cache Penetration)

问题描述:
缓存穿透指的是恶意或非法访问请求查询一个不存在的缓存数据,导致该查询请求绕过缓存直接访问数据库,从而引起数据库的压力增大。

解决方案:

  • 缓存空对象(Cache Null Object):对于不存在的数据,也将其缓存起来,设置一个较短的过期时间,防止恶意请求多次访问。
  1. 缓存雪崩(Cache Avalanche)

问题描述:
缓存雪崩指的是缓存中大量的缓存数据同时过期失效,导致大量的请求直接访问数据库,从而造成数据库压力剧增,甚至引发系统崩溃。

解决方案:

  • 缓存失效时间随机化:设置缓存的失效时间随机分布,避免大量缓存同时过期。
  • 分布式锁:在缓存失效时,使用分布式锁控制同时只有一个请求更新缓存,避免缓存失效时大量请求同时更新。
  • 热点数据永不过期:对于重要的热点数据,设置永不过期,保证即使其他数据失效也不影响重要数据的访问。
  1. 缓存击穿(Cache Miss)

问题描述:
缓存击穿是指某个热点数据过期或被删除,在数据未来得及被缓存之前,大量请求直接打到数据库上,引起数据库宕机

解决方案:

  • 设置热点数据永不过期:对于热点数据,采用永不过期的方式,确保即使缓存失效也能保持访问的稳定性。
  • 互斥锁(Mutex Lock):在缓存失效时,使用互斥锁控制只有一个请求能够更新缓存,其他请求等待更新完成后再获取数据。
  • 预先加载(Preloading):提前加载热点数据到缓存中,确保即使缓存失效时也能快速从缓存中获取数据。

十、安全对一套程序来说至关重要,请说说在开发中应该注意哪些安全机制?

使用验证码防止注册机灌水

使用预处理,绑定参数,参数过滤转义,防止sql注入

使用token防止远程提交,使用token验证登录状态

十一、Laravel的依赖注入实现原理

依赖注入:不通过 new() 的方式在类内部创建依赖类对象,而是将依赖的类对象在外部创建好之后,通过构造函数、函数参数等方式传递(或注入)给类使用
实现原理:laravel容器包含控制反转和依赖注入,使用起来就是,先把对象bind好,需要时可以直接使用make来取就好

十二、什么是静态延迟绑定

class ParentClass {
    public static function who() {
        echo __CLASS__;
    }

    public static function test() {
        static::who(); // 此处使用的是 static::,表示调用该方法的实际类
    }
}

class ChildClass extends ParentClass {
    public static function who() {
        echo __CLASS__;
    }
}

// 调用 ChildClass 的 test 方法
ChildClass::test();// 返回 ChildClass

静态延迟绑定,即在类内部用来代表类本身的关键字部分不是在类编译时固定好,而是当方法被访问时动态的选择来访者所属的类。可以理解为,定义父类时,提前设置子类访问该静态方法。

十二、session与cookie区别

cookie数据存放在客户的浏览器上,session数据放在服务器上

cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,如果主要考虑到安全应当使用session

session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,如果主要考虑到减轻服务器性能方面,应当使用COOKIE

单个cookie在客户端的限制是3K,就是说一个站点在客户端存放的COOKIE不能3K

十三、Innodb下创建表,表中不创建主键索引,创建一般索引后,查询逻辑是怎样

  1. 隐式主键的创建
    如果你在创建表时没有定义主键索引,InnoDB会自动创建一个6字节的ROWID作为隐式主键。这是为了保证每一行有一个唯一标识符。
  2. 查询逻辑
    当你对这个表执行查询时,查询逻辑会根据查询条件来决定使用什么索引。
    如果你的查询条件包含了索引列(例如name列),InnoDB会使用一般索引来加速查询。查询流程如下:

查找索引:首先,InnoDB会在idx_name索引中查找符合条件的索引项。
获取ROWID:通过索引项找到对应的ROWID(隐式主键)。
查找数据:使用ROWID在聚簇索引(B+树)中找到实际的数据行。

十四、php 怎么支持多个并发

PHP通常运行在Web服务器(如Apache、Nginx等)中,这些服务器处理并发请求的方式决定了PHP支持并发的能力。PHP本身并不是多线程的,但它可以通过Web服务器的进程模型来处理并发请求。
以Nginx为例,Nginx本身是一个异步的、事件驱动的Web服务器,它不能直接执行PHP脚本,但可以通过FastCGI协议与PHP-FPM(FastCGI Process Manager)协作。

特点:PHP-FPM管理一个PHP进程池,可以启动多个PHP进程来处理请求。
并发:Nginx处理并发连接,多个请求通过FastCGI传递给PHP-FPM,PHP-FPM中的多个进程并发处理请求。
PHP执行:每个PHP进程独立处理一个请求。
优点:高效,性能好,易于配置和扩展。
缺点:需要额外配置,但这是最常用和推荐的方式。

十五、有两个文件,大小都超过了 1G,一行一条数据,每行数据不超过 500 字节,两文件中有一部分内容是完全相同的,请写代码找到相同的行,并写到新文件中。PHP 最大允许内存为 255M

解题思路:由于文件较大,需要注意内存的使用,可以将第一个文件逐行读取转换为MD5值,存入数组。第二个文件也逐行读取转换为MD5,并判断每个MD5是否存在于刚才的数组中。

十六、请用 SHELL 统计 5 分钟内,nginx 日志里访问最多的 URL 地址,对应的 IP 是哪些?


#!/bin/bash

# 设置时间范围
start_time=$(date -d "5 minutes ago" "+%d/%b/%Y:%H:%M:%S")
end_time=$(date "+%d/%b/%Y:%H:%M:%S")

# 统计访问最多的URL地址和对应的IP地址
awk -v start_time="$start_time" -v end_time="$end_time" '$4 > "["start_time && $4 < "["end_time {print $1,$7}' access.log | sort | uniq -c | sort -rn | head -10

start_time 和 end_time 分别表示统计的时间范围,这里设置为5分钟前至当前时间
awk 命令用于从日志文件中提取时间、IP地址和URL地址。其中,4表示日志中的时间字段,4表示日志中的时间字段,4表示日志中的时间字段,1 表示日志中的IP地址字段,$7 表示日志中的URL地址字段。
sort 命令用于将提取出来的IP地址和URL地址进行排序
uniq -c 命令用于统计每个IP地址和URL地址的出现次数
sort -rn 命令用于将统计结果按照出现次数从大到小排序
head -10 命令用于只显示出现次数最多的前10个IP地址和URL地址

十七、写一段 shell 脚本实现备份 mysql 指定库(如 test) 到指定文件夹并打包,并删除 30 天前的备份,然后将新的备份推送到远端服务器,完成后送邮件通知


#!/bin/bash

# 备份文件名
BACKUP_NAME="test_$(date +%Y%m%d_%H%M%S).sql"

# 备份目录
BACKUP_DIR="/path/to/backups"

# 本地备份文件路径
BACKUP_FILE="$BACKUP_DIR/$BACKUP_NAME"

# 远端服务器信息
REMOTE_USER="user"
REMOTE_HOST="remote_host"
REMOTE_DIR="/path/to/remote/dir"

# 邮件信息
MAIL_TO="user@example.com"
MAIL_SUBJECT="MySQL Backup Report"
MAIL_BODY="MySQL backup completed successfully."

# 备份 MySQL 数据库
mysqldump -u root -pPASSWORD test > "$BACKUP_FILE"

# 压缩备份文件
tar -czvf "$BACKUP_FILE.tar.gz" "$BACKUP_FILE"

# 删除 30 天前的备份文件
find "$BACKUP_DIR" -type f -name "*.tar.gz" -mtime +30 -delete

# 推送备份文件到远端服务器
scp "$BACKUP_FILE.tar.gz" "$REMOTE_USER@$REMOTE_HOST:$REMOTE_DIR"

# 发送邮件通知
echo "$MAIL_BODY" | mail -s "$MAIL_SUBJECT" "$MAIL_TO"

十八、引用变量

$a = [1,2,3];
foreach ($a as &$v);

foreach ($a as $v);

var_dump($a);

请写出输出结果

第一次循环时,$v使用引用,但循环并没有实际操作,结束时,变量$v仍然引用数组$a的最后一个元素,即3。
第二次循环时,不使用引用。然而,由于$v在上一个循环中引用数组的最后一个元素,所以在这个循环中,$v的值会被修改,并且会影响数组$a。
第一次迭代:$v = 1,结果:$a = [1, 2, 1]
第二次迭代:$v = 2,结果:$a = [1, 2, 2]
第三次迭代:$v = 2,结果:$a = [1, 2, 2]

最终,$a的值变成了array(1,2,2)

十九、有 10 亿条订单数据,属于 1000 个司机的,请取出订单量前 20 的司机

SELECT driver_id,COUNT(*) as count  FROM order 
GROUP BY driver_id 
ORDER BY count desc
limit 20

二十、如何以最少流量消耗,获取一个远程资源(假设1G)的最后10个字节?

可以使用cURL库,并设置Range头部。

$url = 'http://example.com/resource';
$ch = curl_init($url);

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
    'Range: bytes=-10'
));

$response = curl_exec($ch);
curl_close($ch);

echo $response;

二十一、laravel autoload实现原理

Laravel使用Composer自动加载机制来加载类文件。Composer是PHP的一个依赖管理工具,是定义和安装项目所需的依赖包。

Composer的自动加载机制通过composer.json文件中的autoload字段来配置。autoload字段中包含了类的命名空间与类文件的映射关系。当我们使用一个类时,Composer会自动加载对应的类文件。

具体来说,Composer将类的命名空间与类文件的路径相关联,并使用PSR-4规范来实现自动加载。PSR-4规范定义了如何将命名空间映射到文件系统路径。例如,一个类App\Models\User的命名空间可能被映射到app/Models/User.php这个文件。

当我们在代码中使用use语句导入一个类时,Composer会根据autoload字段中的配置来查找对应的类文件,并自动加载它。这样我们就可以直接使用导入的类,而无需手动包含类文件。

此外,Laravel还提供了一些特殊的自动加载机制。比如,composer.json文件中的classmap字段可以用来指定特定的类文件要被加载,而无需遵循PSR-4规范。另外,Laravel还使用了服务提供者来注册应用程序的服务,并通过Composer的自动加载机制来加载这些服务提供者。

总的来说,Laravel的自动加载机制使得我们可以方便地使用命名空间来组织和加载类文件,提高了代码的可维护性和可读性。

  • 24
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值