Skip to main content

PHP 面试题目

一、PHP 基础语法(初级)

  1. PHP 中有哪些数据类型?请举例说明。
    # 标量类型
    int // 整形
    string //字符串
    float //浮点型
    bool //布尔型
    # 复合类型
    array // 数组
    object //对象
    # 特殊类型
    null // 空值
    resource //资源,例如数据库连接等$handle = fopen("a.txt", "r")
    # 伪类型
    mixed // 可接收多重类型(int,string等)
    number // 整形或浮点型
    callback //可调用函数(匿名函数)
    void // 无返回值
  2. ===== 的区别是什么?
    == // 比较值
    === // 比较值和类型,比较严谨
  3. 如何判断一个变量是否已定义且不为 null?
    isset($var):会返回true,当变量存在且不为null,如果未定义,isset()也不会报错
  4. include、require、include_once、require_once 有何区别?
    # 都是用于引入文件, 建议使用*_once
    include // 警告,继续执行,会重复引入,脚本不会终止
    require // 致命错误,中止执行,会重复引入
    include_once // 警告,继续执行,只会引入一次
    require_once // 致命错误,中止执行,引入一次
  5. isset() 和 empty() 的区别?
    isset // 判断变量存在且不为空
    empty // 判断变为0,null,空字符串
  6. PHP 中如何处理错误与异常?try-catch 和 set_error_handler 的使用场景?
    set_error_handler // 处理非异常的传统运行时错误
    try-catch // 捕获异常(如PDO异常) 继承自Throwable
  7. 常见的字符串操作函数有哪些?如 substr, strpos 等。
    # 查找与匹配
    strpos // 查询子串首次出现的位置
    strrpos // 查询子串最后一次出现的位置
    stripos // 不区分大小写查找
    # 截取
    substr // 截取字符串一部分
    str_split // 按字符拆分成数组
    explode // 按分隔符拆分为数组
    implode // 将数组合并为字符串
    # 替换
    str_replace // 替换指定内容
    str_ireplace //不区分大小写替换
    substr_replace //替换指定位置的内容
    # 大小写转换
    strtolower // 转小写
    strtoupper // 转大写
    ucfirst // 首字母大写
    lcfirst // 首字母小写
  8. 如何获取当前脚本的文件路径?
    # 当前文件的完整路径包括文件名
    echo __FILE__
    # 当前脚本所在的目录路径(不包含文件名)
    echo __DIR__
  9. 变量和常量的定义方式及区别?
    1. 变量: $var = value, 可变,局部/全局可见
    2. 常量: const = value和define("name","value"), 不可变,全局可见
  10. 引号(单引号、双引号、heredoc、nowdoc)之间的区别?
    1. 单引号:
      • 不会解析变量
      • 除了\和',不会解析转移字符
    2. 双引号:
      • 解析变量
      • 常见字符串,如\n,\t,"
    3. heredoc类似双引号
    4. newdoc类似单引号
  11. 什么是类型自动转换?什么时候会触发?
    1. 指当前运算或比较中涉及不同类型的值时,php自动将变量转换为适当的数据类型行为。
  12. 什么是可变函数?什么是匿名函数?
    1. 默认参数一定要在非默认参数之后
    2. 默认参数可以是表达式
    3. 避免默认值时可变数据类型
  13. use 在闭包中的作用? use 从外部作用域引入变量,使得闭包可以访问其他外部的变量值
    $outside = 'world';
    $greet = function () use ($outside) {
    return "Hello, $outside!";
    };
    echo $greet(); // 输出:Hello, world!

二、PHP 面向对象编程(初中级)

  1. public、protected、private 的作用及区别。
    # 访问修饰符
    public // 任何地方都可以访问(类外、子类、类内部)
    protected // 类内部或者子类中访问
    private // 私有,类自身内部访问
  2. 接口(interface)和抽象类(abstract class)的区别.
    interfaceabstract
    8.0以上可以实现default可以实现包含方法
    不能有属性有属性,修饰符
    无构造方法可以有
    多实现单继承
    都必须为publicpublic/protected
  3. 魔术方法 __construct()__get()__set()__call() 有何用途?
    __construct // 构造函数,创建对象时自动调用,初始化对象属性
    __get // 访问未定义或不可访问属性时触发
    __set // 未定义或不可访问属性赋值时触发
    __call // 调用未定义的方法时触发
  4. 什么是依赖注入?如何实现?
    用于将对象所依赖的其他对象(或资源)从外部传入,而不是在类内部创建依赖对象,提高解耦性、可测试性和可维护性
  5. PHP 如何实现多态?举一个接口或继承的例子
    不同的类对相同的方法做出不同的响应
    1、通过接口
    2、通过继承,重写方法
  6. traits 是什么?解决了哪些问题?
    由于类不能多继承,又希望多个类共享一组方法,类似模块引入,使用use ExampleTrait
  7. 设计模式:
    # Singleton数据库连接、缓存服务、日志管理。
    class DB {
    private static $instance;
    private function __construct{}
    public static function getInstance(){
    if (!self::$instance){
    self::$instance = new DB();
    }
    return self::$instance;
    }
    }
    # Factory 工厂模式 据条件返回不同的对象,比如支付系统(支付宝/微信)
    interface Payment {
    public function pay($amount);
    }
    class Alipay implements Payment{
    public function pay($amount){echo "Alipay: $amount";}
    }
    class PaymentFactory{
    public static function create($type):Payment{
    if ($type === 'alipay') return new Alipay();
    }
    }
    # Adapter适配器模式,老接口适配新系统,比如不同邮件服务类统一成一个接口。
    class OldMailer {
    public function sendMail($to,$msg){echo "Sent to $to";}
    }
    class MailAdapter {
    private $mailer;
    public function __construct(OldMailer $mailer){
    $this->mailer = $mailer;
    }
    public function send($recipient,$message){
    $this->mailer->sendMail($recipient,$message)
    }
    }
    # Decorator 装饰器模式,
    ✅ 作用:在不修改原类的前提下,动态扩展其功能。
    ✅ 场景:为日志、缓存、权限等功能增加“包裹层”。
    class UserService {
    public function login($user){
    echo "User login\n";
    }
    }
    class LogDecorator {
    private $service;
    public function __construct(UserService $service){
    $this->service = $service
    }
    public function login($user){
    echo "Log start\n";
    $this->service->login($user);
    echo "Log end\n";
    }
    }
    # Observer观察者模式
    ✅ 作用:对象之间建立发布/订阅关系,一方变更,通知所有监听者。
    ✅ 场景:用户注册后发送邮件/短信通知。
    interface Observer{
    public function update($event);
    }
    class MailService implements Observer{
    public function update($event){
    echo "发送邮件:$event"
    }
    }
    class EventManager{
    private $observers = []
    public function attach(Observer $observer){
    this->observers[] = $observer
    }
    public function trigger($event){
    foreach($this->observers as $obs){
    $obs->update($event)
    }
    }
    }
    # Strategy(策略模式)
    ✅ 作用:封装多个算法,互相可以替换。
    ✅ 场景:计算折扣策略、支付策略、日志策略等。
    interface DiscountStrategy{
    public function getPrice($price)
    }
    class VipDiscount implements DiscountStrategy{
    public function getPrice($price){return $price * 0.8}
    }
    class Cart{
    public function checkout($price,DiscountStrategy $strategy){
    return $strategy->getPrice($price);
    }
    }
    模式名用于何时?关键词
    单例只要一个对象全局唯一
    工厂隐藏创建细节创建对象
    策略运行时替换行为多种算法
    装饰器增加功能包裹增强
    适配器改接口名或结构转接口
    观察者通知一批监听者发布/订阅
    责任链多个处理器顺序尝试依次处理
    代理控制访问(懒加载、安全)代替访问

三、PHP 进阶与常用功能(中级)

  1. 使用 PDO 操作数据库的流程?如何防止 SQL 注入?
    1.预处理语句和绑定参数,避免直接拼接字符串形成SQL
    2.PDO会自动将参数转义,防止恶意注入
    3.关闭PDO::ATT_EMULATE_PREPARES(模拟预处理)可以增强安全性。
  2. 文件上传的处理流程?如何限制类型和大小?
    1. 处理流程:
      1. 表单准备,使用form标签
      2. 用户选择文件并提交表单
      3. 服务器接收文件
        • PHP通过$_FILES超全局变量获取上传信息
        • $_FILE['file']['tmp_name']是文件的临时路径
        • $_FILE['file']['name']是原始文件名
      4. 验证文件大小
        • 检查上传错误码
        • 检查文件大小
        • 检查文件MIME类型或扩展名
      5. 移动文件
        • 用 move_uploaded_file() 将临时文件移动到目标目录
      6. 返回结果
    2. 类型和大小限制
      1. 通过new fileinfo(FILEINFO_MIME_TYPE);
      2. 通过$_FILE['size']来判断大小
  3. 使用 curl 发送 POST 请求的方式?
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL,$url);
    curl_setopt($ch, CURLOPT_POST, true); // 启动POST请求
    # application/x-www-form-urlencoded使用
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); // 编码为query string
    # 发送json使用
    curl_setopt($ch, CURLOPT_HTPHEADER, ["Content-Type:application/json"])
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); // json格式
    # 发送multipart/form-data使用
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data)
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);// 返回结果而不是输出
    $response = curl_exec($ch);
    curl_close($ch);
    echo $response;
  4. 如何设置和读取 cookie / session?
    setcookie(name, value, expire, path, domain, secure, httponly);
    params:
    name: cookie 名称
    value: 值
    expire: 到期时间(时间戳)
    path: 有效路径(/代表整个站点)
    httponly: 方式javascript访问,提高安全性
    #读取cookie
    $_COOKIE['username']
    # 启用session
    session_start() // 必须写到最顶部
    $_SESSION['user_id'] = 123
    unset($_SESSION['user_id']) // 删除某个session值
    session_destory() // 销毁session
  5. Composer 是什么?如何创建自己的 Composer 包?
    # 安装依赖包(根据composer.json)
    composer install
    # 添加新依赖包
    composer require monolog/monolog
    # 自动加载类
    require 'vendor/autoload.php'
  6. PHP 性能优化建议有哪些?如 opcache、output buffer?
    1. 启用OPcache
      • 缓存php脚本的编译结果(字节码),避免每次请求都重复解析
        # php.ini 中启用
        opcache.enable=1
        opcache.memory_consumption=128
        opcache.interned_strings_buffer=8
        opcache.max_accelerated_files=10000
        opcache.validate_timestamps=1
    2. 启用Output Buffering(输出缓冲)
      • 避免频繁I/O写入,提高传输效率.
  7. 如何读取 JSON 并将其转为 PHP 数组?
    $json = '{"name": "Alice", "age": 25, "email": "alice@example.com"}';
    $data = json_decode($json, true); // 第二个参数为 true 表示转为数组
    print_r($data);

四、Laravel 核心知识(中高频)

  1. Laravel 的请求生命周期简述.
    1. 入口文件(public/index.php)
      • 所有请求都首先经过(public/index.php),laravel应用入口.
      • 它会加载自动加载器和启动laravel应用实例:
        require __DIR__.'/../vendor/autoload.php';
        $app = require_once __DIR__.'/../bootstrap/app.php';
    2. 生成内核(Kernel)
      • Laravel 会创建一个HTTP Kernel实例(App\Http\Kernel),它定义了中间件和请求流程.
      • 核心职责是处理请求并返回响应:
        $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
        $response = $kernel->handle($request);
    3. 处理中间件
      • 请求依次经过全局中间件路由中间件
        • 用户认证
        • CSFR验证
        • 请求日志记录
        • 内容预处理等
    4. 路由分发
      • 到达路由系统,根据URI和请求方法(GET/POST等)匹配定义的路由。
      • laravel会调用对应的Controller或闭包函数来处理
    5. 控制器处理
      • 执行据具体逻辑,例如:读取数据,调用服务类,返回视图等
    6. 生成响应
      • 控制器会返回一个响应对象(Illuminate\Httpp\Response),可能是:
        • 页面HTML
        • JSON数据
        • 文件下载
        • 重定向等
    7. 发送响应给浏览器
      $response->send()
    8. 中止中间件执行
      • Laravel 执行中间件的terminate()方法
    Browser Request

    public/index.php (入口)

    Bootstrap Laravel

    HTTP Kernel (App\Http\Kernel)

    [全局中间件处理]

    路由匹配(RouteServiceProvider)

    [路由中间件处理]

    控制器/闭包执行

    生成响应 (Response)

    发送响应 (send)

    终止中间件(terminate)
  2. Route::get() 和 Route::resource() 的区别及使用场景。
    get() 定义一个响应GET方法的简单路由,比如:首页、详情页等
    resource() 定义一组restful路由,资源管理,不使用可以用only限制
  3. 如何创建中间件?如何进行路由分组?
    1. 使用命令artisan来创建
    php artisan make:middleware checkAge
    2. 在中间件中编写逻辑
    3. 注册中间件
    4. 路由中使用中间件
    路由分组分为带中间件和带前缀
    # 带中间件
    Route:middleware(['auth'])->group(function(){
    Route::get('/', function(){
    return view('dashboard')
    })
    })
    # 带前缀
    Route::prefix('admin')->group(function(){
    Route::get('/user', [UserController:class, 'index']);
    })
  4. 什么是服务容器?如何绑定并解析服务?
    1. 容器的作用:
      • 自动解析类的依赖关系
      • 将接口绑定到具体实现
      • 实现控制反转(IOC)和依赖注入
    2. 场景:
      • 控制器中自动注入依赖类
      • 接口绑定到某个实现
      • 绑定单例、闭包、类等
    3. 绑定解析
      • 通常在AppServiceProvider中register()方法中内定义
      • 自动注入解析
      • 手动解析
  5. Laravel 的依赖注入有哪几种方式?构造函数、服务提供者、闭包绑定。
    1. 构造函数注入
    2. 方法注入
    3. 服务提供者绑定,配置接口和实现绑定
    4. 闭包绑定:复杂实例化逻辑或参数传递实现。
  6. Eloquent ORM 的基本查询写法(where、orWhere、with、has)。
    1. where基本条件
      $users = User::where('status', 'active')->get();

      select * from users where status ='active';
    2. orWhere 或条件查询
      $users = User::where('status', 'active')->orWhere('is_admin', true)->get();
      SELECT * FROM users WHERE status = 'active' OR is_admin = true;
    3. with 预加载关联模型
      $users = User::with('posts')->get();
      -- 第一个查询:获取用户
      SELECT * FROM users;

      -- 第二个查询:获取这些用户的关联文章
      SELECT * FROM posts WHERE user_id IN (1, 2, 3, ...);
      # 嵌套关联预加载
      $users = User::with('posts.comments')->get();
      $users = User::with(['posts'=>function($query){
      $query->where('status', 'published');
      }])
    4. has 过滤"有某个关联"的模型
      $users = User::has('posts')->get();
      # sql
      SELECT * FROM users WHERE EXISTS (
      SELECT * FROM posts WHERE posts.user_id = users.id
      );
      # 限制关联记录数量:
      $users = User::has('posts', '>=', 5)->get();
  7. Laravel 如何避免 N+1 查询问题?(with vs load)
    1. with 主动预加载,解决n+1
    2. load是临时操作,模型已经存在,相比较with是额外的sql。
  8. Laravel 的事件与监听器如何工作?
    Event: 表示某个事件发生
    Listener: 表示当前发生时执行的逻辑
    1. 创建事件和监听器
    php artisan make:event UserRegister
    php artisan make:listener SendEmail --event=UserRegister
    # 生成两个文件
    app/Events/UserRegistered.php
    app/Listeners/SendWelcomeEmail.php
    2. 定义事件类
    3. 定义监听器类
    4. 注册事件和监听器 在 app/Providers/EventServiceProvider.php 中
    5. 触发事件在控制器中 添加比如:event(new \App\Events\UserRegistered($user));
  9. 队列如何配置与使用?有哪些驱动?
    1. Laravel队列基础概念
      • Job: 表示一个任务
      • Queue: 任务排队通道,可按优先级区分不同队列
      • Worker: 后台"工人"进程, 持续监听并处理队列任务.
      • Queue Driver: 底层存储队列任务的系统(数据库、redis)
    2. 步骤:
      1. 选择队列驱动,在.env中配置QUEUE_CONNECTION=database
        驱动描述
        sync同步执行
        database存储在数据库
        redisredis
        beanstalkd高性能队列
        sqs亚马逊sqs
        null丢弃所有队列任务(测试)
      2. 创建Job表
        php artisan queue:table
        php artisan migrate
      3. 创建一个Job
        php artisan make:job SendEmail
        class SendWelcomeEmail implements ShouldQueue
        {
        use Queueable;

        protected $user;

        public function __construct($user)
        {
        $this->user = $user;
        }

        public function handle()
        {
        Mail::to($this->user->email)->send(new WelcomeMail($this->user));
        }
        }
      4. 分发Job到队列
        # 在控制器或者服务中调用
        dispatch(new \App\Jobs\SendWelcomeEmail($user));
      5. 启动队列监听Worker
        php artisan queue:work
        # 或使用自动重启的守护进程
        php artisan queue:listen
  10. Laravel 的缓存系统有哪些?如何使用 file/redis 缓存?
    驱动简介
    file缓存存储到文件系统
    redis支持高并发
    database数据库作为缓存存储
    memcached使用Memcached服务
    array临时缓存,仅限当前生命周期
    dynamodbAWS DynamoDB
    配置文件在:config/cache.php,默认驱动在
    'default' => env('CACHE_DRIVER', 'file'),

六、安全与认证(通用 + 框架)

  1. CSRF/XSS 是什么?Laravel/Yii2 如何防御?

    XSS: 注入恶意脚本, 窃取Cookie或控制前端页面
    Laravel: 使用 {{$variable}}转义
    Yii2: Html::encode($content)
    CSRF:
    Laravel: @csrf / VerifyCsrfToken
    Yii2: enableCsrfValidation = true
  2. Laravel 的 csrf_token 如何嵌入表单?

    Blade模版在form标签内加一行
    手动插入token使用csfr_token()函数手动添加。
    所有POST、PUT、PATCH、DELETE都应该加
  3. 如何使用 bcrypt 或 password_hash 加密密码?

    • password_hash 是原生php
    • btypt laravel辅助函数,
    • 推荐方法使用Hash::make('123456') laravel 推荐
  4. Laravel 和 Yii2 如何实现 RBAC 权限控制?

    1. Laravel使用官方推荐包spatie/laravel-permission
      1. 安装扩展
        composer require spatie/laravel-permission
      2. 发布并迁移
        php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
        php artisan migrate
      3. 在模型中引入Trait
      4. 分配角色权限
      5. 验证权限
      6. 中间件控制访问
    2. yii2自带完善的rbac
      1. 基于数据库的
        1. 配置组件authManager:
          'components' => [
          'authManager' => [
          'class' => 'yii\rbac\DbManager',
          ],
          ],
        2. 创建RBAC表结构
          php yii migrate --migrationPath=@yii/rbac/migrations/
        3. 添加角色/权限并赋权
        4. 验证权限
      2. 基于代码的RBAC 'authManager' => ['class' => 'yii\rbac\PhpManager']
  5. 如何防止 SQL 注入(框架/原生)?

    做法说明
    输入验证与过滤filter_var()htmlspecialchars()
    最小权限原则数据库账号仅授予必要权限
    日志记录与监控审查异常访问行为
    关闭错误信息输出禁止生产环境显示 SQL 报错信息
    技术防注入推荐写法
    原生 PHPPDO + Prepared Statements
    Laravel使用 Eloquent / Query Builder,避免拼接 SQL
    Yii2使用 ActiveRecord / 参数绑定的原生 SQL
  6. 如何防止session被劫持

    1. 使用https
    2. 设置HttpOnly & Secure Cookie
    3. 绑定Session到IP/User-Agent
    4. 定期更新SessionID

七、数据库 & SQL 优化

  1. 编写 SQL:查询 orders 表中金额 >100 的 paid 状态订单总数。

    select * from orders where amount>100 and status = 'paid'
  2. 写一条 SQL:查询每个用户的订单总金额

    select sum(amount) from orders group by userid;
  3. 什么是索引?哪些字段适合建立索引?哪些不适合?

    1. 索引通常以B+树(默认的Innodb引擎),对某些字段进行排序
      • 提高查询效率(SELECT)
      • 提高JOIN查询性能
      • 提高Where/Order By/Group By等操作
    2. 适合索引
      • 经常做为查询条件WHERE的自带
      • 经常用于排序Order By的字段
      • 经常用于连接JOIN ON的字段
      • 经常用于分组GROUP BY的字段
      • 唯一性要求高的字段
      • 外键字段,经常需要连表
    3. 不适合
      • 频繁更新的字段
      • 重复值比较多的字段
      • 查询量较少的字段
      • 大文本字段
      • 数据量极少的表
  4. GROUP BY 与 HAVING 的区别?

    1. GROUP BY是分组依据,结果集按一个或多个字段进行分组
    2. having 筛选分组后的结果
  5. 如何使用 EXPLAIN 分析 SQL 执行计划?

    Explain select * orders from where user_id=101;
    字段说明
    id查询中执行顺序的标识
    select_type查询类型,如 SIMPLE(简单查询)、PRIMARY、SUBQUERY 等
    table正在访问的表名
    type访问类型,性能指标(最好是 consteq_ref,差的是 ALL)
    possible_keys可能使用的索引
    key实际使用的索引
    key_len使用索引的长度
    ref哪个列或常量被用于查找索引
    rows估算需要扫描的行数
    Extra额外信息,如是否使用文件排序、临时表等
  6. Laravel 的事务处理方法?

    1. 使用 DB::transaction() 方法(推荐)
      use Illuminate\Support\Facades\DB;

      DB::transaction(function () {
      // 这里的数据库操作将作为一个事务执行
      DB::table('users')->update(['votes' => 1]);

      DB::table('posts')->delete();
      });
    2. 手动开启、提交和回滚事务
      use Illuminate\Support\Facades\DB;

      DB::beginTransaction();

      try {
      DB::table('users')->update(['votes' => 1]);

      DB::table('posts')->delete();

      DB::commit(); // 提交事务
      } catch (\Exception $e) {
      DB::rollBack(); // 发生异常回滚
      throw $e;
      }
  7. Yii2 中如何进行批量插入? 在 Yii2 中,批量插入(bulk insert)可以使用 yii\db\Command 的 batchInsert() 方法,效率比循环逐条插入更高,适合一次插入多条数据。

    注意事项:

    • batchInsert() 只做写操作,无法触发 AR 的事件和行为(如自动时间戳等),也不会自动验证模型数据
    • 如果需要批量插入且触发事件,需循环调用 $model->save(),性能较低
    • 适合大批量导入或初始化数据时使用
  8. Yii2 事务如何处理

    $transaction = Yii::$app->db->beginTransaction();
    $transaction->commit();

八、部署与运维

  1. Laravel 项目的部署步骤(Nginx + PHP-FPM)
    server {
    listen 80;
    server_name yourdomain.com; # 替换为你的域名或IP

    root /var/www/laravel-app/public;
    index index.php index.html;

    access_log /var/log/nginx/laravel_access.log;
    error_log /var/log/nginx/laravel_error.log;

    location / {
    try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php8.1-fpm.sock; # 根据 PHP 版本调整
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
    }

    location ~ /\.(?!well-known).* {
    deny all;
    }
    }
  2. .env 文件的作用?Laravel 如何区分开发/生产环境?
    • .env是一个环境配置文件,存放应用的环境变量
    • 用于数据库配置、缓存驱动、邮件服务、API秘钥等敏感信息或环境相关配置
    • 避免将敏感信息写到代码中,方便不同环境使用不同配置
    • Laravel 启动时通过 vlucas/phpdotenv 读取 .env 并加载到 PHP 的环境变量中($_ENV、$_SERVER
      • Laravel 通过 .env 文件中的 APP_ENV 变量区分环境
        APP_ENV=local       # 本地开发环境
        APP_ENV=production # 生产环境
      • 在代码中可以通过 app()->environment() 或 env('APP_ENV') 获取当前环境,做不同处理:
        if (app()->environment('production')) {
        // 生产环境逻辑
        }

        if (app()->environment(['local', 'testing'])) {
        // 开发或测试环境逻辑
        }
  3. Laravel 中如何使用 config:cache、route:cache 等命令?
    1. php artisan config:cache
      • 作用:将所有配置文件(config/*.php)合并并缓存成一个文件,避免每次请求都加载多个配置文件,提升性能。
      • 生产环境部署时,一般都会执行此命令。
    2. php artisan route:cache
      • 作用:将所有路由定义缓存为一个文件,提高路由注册速度。
      • 使用场景:路由定义较多,且路由不会频繁修改时使用。适合生产环境。
  4. Laravel 的 storage 目录要赋予什么权限? storage目录用于保存缓存文件、日志、session文件、编译后的视图等。
    1. 赋予写权限
      # 给 storage 和 bootstrap/cache 目录赋予 755 权限(推荐)
      chmod -R 755 storage bootstrap/cache
      # 将 Web 服务器用户加入文件夹所属用户组
      chown -R www-data:www-data storage bootstrap/cache
  5. Yii2 如何部署?入口文件在哪?
    1. 上传项目

    2. 安装依赖

    3. 设置目录权限

    4. 配置nginx

    5. 设置数据库连接

    6. 初始化init

      入口文件为web/index.php

  6. Laravel 队列如何守护运行?如何在服务器中执行 supervisor?
    1. linux 安装supervisor
    2. 配置laravel worker
  7. 如何排查 Laravel 项目的 500 错误?日志路径在哪里?
    1. 查看laravel错误日志
      storage/logs/laravel.log
    2. .env开启调试
      APP_DEBUG=true
      APP_ENV=local
    3. 出现问题原因:
      原因描述
      权限问题storage/bootstrap/cache/ 不可写
      .env 错误配置语法错误或缺少密钥
      缓存问题运行 php artisan config:clearroute:clear 清除缓存
      Composer 问题未正确安装依赖或自动加载器异常
      PHP 扩展缺失缺少 mbstringopenssl 等扩展
      数据库连接失败.env 中数据库配置错误

九、 PHP Swoole


  1. Swoole 核心

    核心能力说明
    🌐 异步网络通信内建 TCP/UDP/HTTP/WebSocket 服务器,无需 Apache/Nginx
    🧵 协程类似 Go 的协程调度,可轻松处理 10w+ 并发请求
    🪝 常驻内存脚本常驻、性能飞跃、避免重复加载
    📤 异步任务支持任务下发、异步处理,适合重操作或 IO 密集型任务
    💼 多进程主进程 + Worker + Task + 自定义子进程
  2. Swoole 电商场景

    场景Swoole 用法说明
    秒杀接口高并发协程 + Redis 限流 + 内存排队降低 DB 压力、实现“抢单”快速响应
    订单处理 异步任务投递处理库存/支付回调避免用户等待,后台慢慢处理
    WebSocket 消息实时推送订单状态、客服消息消息系统:客服、物流、系统通知
    接口聚合服务多个服务间 HTTP 异步请求合并返回比如结算页汇总商品/库存/运费
    异步任务队列比如注册送券、下单发邮件、日志投递使用 TaskWorker 或自定义进程
    接口网关基于 Swoole 搭建 API 网关服务集中限流/鉴权/转发,替代传统 Nginx 网关

综合性问题

  1. Laravel 和 Yii2 在架构设计上的优劣对比?

    方面LaravelYii2
    模块支持支持包管理(Composer 包),无模块系统但支持模块包原生支持模块(Module)概念,方便大型应用拆分
    扩展包生态极其丰富,社区活跃,几乎所有功能都有成熟包生态较 Laravel 小,但官方和社区扩展稳定,适合企业级开发
    事件与中间件机制事件驱动,支持事件监听与广播,中间件链灵活事件驱动,行为系统灵活,中间件支持较晚加入,功能较 Laravel 简单
    方面LaravelYii2
    性能性能一般,依赖许多组件,启动稍慢,适合中大型应用性能优越,框架轻量,启动快,适合对性能要求较高的应用
    缓存支持多种缓存驱动,内置支持 Redis、Memcached 等多缓存驱动,支持 Redis、Memcached,缓存机制高效
    数据库查询Eloquent 方便,复杂查询语法直观,但性能稍逊Query Builder 性能优秀,支持复杂 SQL 优化,适合大数据量操作
  2. 你如何设计一个高并发接口?有哪些防护机制?

    1. 接口性能优化
      • 轻量设计: 接口只返回必要数据,避免复杂业务逻辑和荣誉数据处理
      • 异步处理:耗时操作(发送邮件、日志记录等)放到异步队列,快速返回
      • 数据库优化:
        • 避免全表扫描,合理使用索引。
        • 避免N+1查询.
        • 使用缓存减少压力
      • 缓存机制
        • 数据缓存热点数据
        • 页面缓存或接口缓存,降低重复计算
    2. 架构设计
      • 负载均衡
      • 水平扩展: 多台服务器部署接口服务
    3. 限流与降级
      • 限流策略
        • 全局限流: 对整个接口的访问做限制,最大请求数
        • 用户限流: 基于用户身份(IP, token)限流,防止恶意刷接口
        • 漏桶/令牌桶算法: 常用的平滑限流算法
      • 降级策略:
        • 当系统压力过大时,主动拒绝低优先级请求或返回降级数据
        • 预设降级接口,保证核心业务有限处理
  3. 描述一次线上事故处理流程,如何快速定位问题?

    1. 查看异常
    2. 紧急快速响应,确定事故等级
    3. 日志排查与问题定位确定定位角度
      • 最近部署?
      • 接口响应慢?数据库锁?
      • 单一用户/全体用户
      • 是否影响所有服务还是单个节点
    4. 问题修复与验证
    5. 通知与总结
  4. 如果让你重构一个大型遗留系统,你的步骤是什么?

    1. 采用分段式渐进式重构
    2. 重构的8个核心
      • 业务与代码调研
      • 建立测试
      • 代码结构重构为可维护的层级结构
      • 重构配置与依赖
      • 数据库结构审查与优化
      • 核心模块重构(优先顺序由简到复杂)
  5. 如何对 API 添加版本控制?

    考虑使用路径版本控制

PHP WSL2 安装步骤

  1. 安装WSL2
    # 安装wsl命令
    wsl --install
    # 查看可用发行版列表
    wsl --list --online
    # 安装发行版
    wsl --install -d <DistroName>
    # 更改安装的默认Linux分发版
    wsl --install -d <Distribution Name>
    # 列出Linux发行版
    wsl -l -v
    # 版本设置为 WSL 1 或 WSL 2 例如:wsl --set-version Ubuntu-20.04 2
    wsl --set-default-version <Version#>
    # 更新和升级软件包
    sudo apt update && sudo apt upgrade
  2. 安装PHP环境
     #添加 ondrej/php PPA(提供多版本 PHP)
    sudo apt install software-properties-common -y
    sudo add-apt-repository ppa:ondrej/php
    sudo apt update
    # 安装php7.4和常用扩展
    sudo apt install php7.4 php7.4-cli php7.4-mysql php7.4-curl php7.4-mbstring php7.4-xml php7.4-zip php7.4-redis php7.4-fpm -y
    # 验证版本
    php -v
    # 验证fpm是否启动
    sudo service php7.4-fpm status #output: /run/php/php7.4-fpm.sock
    # 可选: 固定PHP版本
    sudo update-alternatives --install /usr/bin/php php /usr/bin/php7.4 74
    sudo update-alternatives --config php
    # 补充建议(可选)
    curl -sS https://getcomposer.org/installer | php
    sudo mv composer.phar /usr/local/bin/composer
    # 安装phpmyadmin
    sudo apt install phpmyadmin
  3. 安装Mysql环境
    # 升级依赖包
    sudo apt update
    # 安装必要依赖
    sudo apt install libaio1 libncurses5 -y
    # 安装mysql5.7tar包
    https://downloads.mysql.com/archives/get/p/23/file/mysql-server_5.7.42-1ubuntu18.04_amd64.deb-bundle.tar
    # 解压包
    tar -xvf mysql-server_5.7.42-1ubuntu18.04_amd64.deb-bundle.tar
    # 安装包
    sudo dpkg -i *.deb
    # 强力修复并按照
    sudo apt install -f -y
    # 再次尝试安装
    sudo dpkg -i *.deb
    # 启动 MySQL 服务
    sudo service mysql start
  4. 安装Redis数据
    # 安装默认版本
    sudo apt install redis-server -y
    sudo service redis-server start
  5. 安装nginx服务
    sudo apt update
    # 安装nginx服务
    sudo apt install nginx -y
    # 启动服务
    sudo service nginx start
    server {
    listen 8088;
    server_name localhost;

    root /home/<your_user>/yii2-app/web; # <-- 替换为 Yii2 项目 web 目录
    index index.php index.html;

    access_log /var/log/nginx/yii2_access.log;
    error_log /var/log/nginx/yii2_error.log;

    charset utf-8;

    location / {
    try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
    include fastcgi_params;

    fastcgi_pass unix:/run/php/php7.4-fpm.sock; # 或 127.0.0.1:9000
    fastcgi_index index.php;

    # 关键参数:告诉 PHP 要执行哪个脚本文件
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    # 禁止访问隐藏文件 (.git/.env 等)
    location ~ /\.(?!well-known).* {
    deny all;
    }

    # 禁止直接执行 /assets 下的 .php 文件
    location ~ ^/assets/.*\.php$ {
    deny all;
    }

    # 静态文件优化(缓存)
    location ~* \.(jpg|jpeg|png|gif|css|js|ico|woff|woff2|ttf|svg|eot)$ {
    expires 7d;
    access_log off;
    log_not_found off;
    }
    }
    # nginx配置详解
    # 表示匹配所有以.php结尾的URL. ~表示使用正则匹配,\.是转义的点,\.php$匹配字符串以.php结尾
    location ~ \.php$ {
    # 包含Nginx提供的一组标准FastCGI参数,是必须得信息比如:
    # QUERY_STRING
    # REQUEST_METHOD
    # CONTENT_TYPE
    # SCRIPT_NAME
    include fastcgi_params;
    # 告诉Ningx把PHP请求发送给谁处理,表示Unix套接字与PHP-FPM通信
    fastcgi_pass unix:/run/php/php7.4-fpm.sock;
    # 这行高度php-fpm要运行哪个php文件
    # $doucment_root是上面配置的root路径
    # $fastcgi_script_name 是当前请求的路径,比如/index.php
    # 命令路径会传给PHP-FPM去执行这个文件
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }