反补面试官PHP

307 阅读8分钟

PHP

  • php 的垃圾回收机制

    • PHP 使用了引用计数 (reference counting) GC 机制
    • 每个对象都内含一个引用计数器 refcount,每个 reference 连接到对象,计数器加 1。当 reference 离开生存空间或被设为 NULL,计数器减 1。当某个对象的引用计数器为零时,PHP 知道你将不再需要使用这个对象,释放其所占的内存空间
  • session 与 cookie (腾讯云一面

    • 区别
      • 存放位置:Session 保存在服务器,Cookie 保存在客户端
      • 存放的形式:Session 是以对象的形式保存在服务器,Cookie 以字符串的形式保存在客户端
      • 用途:Cookies 适合做保存用户的个人设置,爱好等,Session 适合做客户的身份验证
      • 路径:Session 不能区分路径,同一个用户在访问一个网站期间,所有的 Session 在任何一个地方都可以访问到。而 Cookie 中如果设置了路径参数,那么同一个网站中不同路径下的 Cookie 互相是访问不到的
      • 安全性:Cookie 不是很安全,别人可以分析存放在本地的 COOKIE 并进行 COOKIE 欺骗,考虑到安全应当使用 session
    • 联系
      • Session 需要借助 Cookie 才能正常工作。如果客户端完全禁止 Cookie,Session 将失效!因为 Session 是由应用服务器维持的一个 服务器端的存储空间,用户在连接服务器时,会由服务器生成一个唯一的 SessionID, 用该 SessionID 为标识符来存取服务器端的 Session 存储空间。而 SessionID 这一数据则是保存到客户端,用 Cookie 保存的,用户提交页面时,会将这一 SessionID 提交到服务器端,来存取 Session 数据。这一过程,是不用开发人员干预的。所以一旦客户端禁用 Cookie,那么 Session 也会失效
  • 函数内部 static 和 global 关键字的作用

    • static 是静态变量,在局部函数中存在且只初始化一次,使用过后再次使用会使用上次执行的结果; 作为计数,程序内部缓存,单例模式中都有用到
    • global 关键字,引用全局变量,wordpress中大量用到,如面向过程开发
    • static 静态方法,是类的成员方法,但不需要实例化类可直接使用
    • GLOBAL 在函数内部使用具有全局作用域的变量,如GLOBAL['a']
  • 子类重写父类的 protected 方法有什么限制?或者说有什么要遵守的规则

    • final修饰的类方法不可被子类重写
    • PHP是否重写父类方法只会根据方法名是否一致判断(5.3以后重写父类方法参数个数必须一致)
    • 重写时访问级别只可以等于或者宽松于父类 不可提升访问级别
  • PHP文件末尾是否应该加 ?> 结束符号,为什么?

    • 主要防止 include,require引用文件,把文件末尾可能的回车和空格等字符引用进来
    • 还有一些函数必须在没有任何输出之前调用,就会造成不是期望的结果
  • 使用 PHP 下载网络图片,有哪些方法?

    • 1.file_get_contents
    • 2.readfile读取内容
    • 3.fopen系列函数
    • 4.curl
  • 语句include和require的区别是什么?为避免多次包含同一文件,可用什么语句代替它们 (腾讯云一面)

    • include产生一个warning,而require产生直接产生错误中断
    • require在运行前载入
    • include在运行时载入
  • 简述 private、 protected、 public修饰符的访问权限

    • private : 私有成员, 在类的内部才可以访问
    • protected : 保护成员,该类内部和继承类中可以访问
    • public : 公共成员,完全公开,没有访问限制
  • __autoload()方法的工作原理是什么

    • 使用这个魔术函数的基本条件是类文件的文件名要和类的名字保持一致
    • 当程序执行到实例化某个类的时候,如果在实例化前没有引入这个类文件,那么就自动执行__autoload()函数
    • 这个函数会根据实例化的类的名称来查找这个类文件的路径,当判断这个类文件路径下确实存在这个类文件后就执行include或者require来载入该类,然后程序继续执行,如果这个路径下不存在该文件时就提示错误
    • 使用自动载入的魔术函数可以不必要写很多个include或者require函数
    • spl_autoload_register
  • 正则表达式

    • 通用原子: \d:十进制0到9、\D:取反、\w:数字、字母、下划线、\W:取反、\s:空白符、\S:除了空白符
    • 元字符:.:除了换行符之外的任意字符、*:匹配前面的内容出现0次、1次、多次、?:匹配前面的内容出现0次、1次、^:必须以它开头、$:必须以它结尾、+:一次或多次、{n}:n次、{n,}、{n,m}、[]、()、
    • 修正模式:i:不区分大小写、U:取消贪婪模式、x:忽略空白符
    • 示例
      //demo1
      $str = '中文';
      $pattern = '/[\x{4e00}-\x{9fa5}]+/u';
      preg_match($pattern,$str,$match);
      var_dump($match);
      
      //demo2
      //以139为开头的11位手机号码
      
      $str = '13982929292';
      $pattern = '/^139\d{8}$/';
      preg_match($pattern,$str,$match);
      var_dump($match);
      
      //demo3
      //请匹配所有img标签中的src的值
      
      $str = '<img alt="焦家村" id="sanhuan" src="langbei.jpg" />';
      $pattern = '/<img.*?src="(.*?)".*?\/?>/i';
      preg_match($pattern,$str,$match);
      var_dump($match);
      
  • 文件及目录处理

    • 打开模式fopen

      • r只读方式打开,将文件指针指向文件头
      • r+读写方式打开,将文件指针指向文件头
      • w写入方式打开,将文件指针指向文件头并将文件大小截为零。如果文件不存在则尝试创建之
      • w+读写方式打开,将文件指针指向文件头并将文件大小截为零。如果文件不存在则尝试创建之
      • a写入方式打开,将文件指针指向文件末尾。如果文件不存在则尝试创建之
      • a+读写方式打开,将文件指针指向文件末尾。如果文件不存在则尝试创建之
    • 写入函数

      • fwrite()写入文件(可安全用于二进制文件)
    • 读取函数

      • fread()读取文件
      • fgets()从文件指针中读取一行
      • fgetc()从文件指针中读取字符
      • 关闭函数:fclose()
    • 不需要fopen打开的函数

      • file_get_contents()
      • file_put_contents()
    • 其他读取函数

      • file()把整个文件读入一个数组中
      • readfile()输出文件
    • 示例

      //demo1
      $file = './hello.txt';
      //打开文件
      $handle = fopen($file, 'r');
      //将文件的内容读取出来,在开头加入hello world
      $content = fread($handle, filesize($file));
      //将拼接好的字符串回到文件当中
      $content = 'hello world'.$content;
      fclose($handle);
      $handle = fopen($file,'w');
      fwrite($handle,$content);
      fclose($handel);
      
      //demo2
      $dir = './test';
      //打开目录
      //读取目录中的文件
      //如果文件类型是目录,继续打开目录
      //读取子目录的文件
      //如果文件类型是文件,输出文件名称
      //关闭目录
      function loopDir($dir)
      {
          $handle = opendir($dir);
          while(false !== ($file = readdir($handle)))
          {
              if($file != '.' && $file != '..')
              {
                  echo $file."\n";
                  if (filetype ($dir.'/'.$file) == 'dir')
                  {
                      loopDir($dir.'/'.$file);
                  }
              }
          }
      }
      loopDir($dir);
      
  • 魔术方法

    • 针对变量的__get(),__set(),__isset(),__unset() 通过__get(),__set(),__isset(),__unset()来分别实现对不存在属性的赋值、读取、判断属性是否设置、销毁属性。可以在类里面定义一个数组变量,来保存所有属性的名称与值
    • 针对方法的__call(),__callstatic() 通过__call(),__callstatic()来实现对不存在的方法和静态方法的调用。__callstatic也必须声明为static。 当写__call()方法时,就可以加上value参数,来对不同的函数名称进行操作。 PHP里面读取类的属性或者调用方法用 ->,读取静态的则需要用::。父类方法也需要用::
    • __toString方法在将一个对象转化成字符串时自动调用,比如使用echo打印对象时,如果类没有实现此方法,则无法通过echo打印对象
    • 针对把类当成函数输出的__invoke 类不能直接当成函数调用,比如echo $object(); 如果object类里面定义了__invoke()函数,那么当把类当做函数调用的时候,会自动调用__invoke()函数
  • 接口与抽象类

    • 抽象类
      • 抽象类是指在 class 前加了 abstract 关键字且存在抽象方法(在类方法 function 关键字前加了 abstract 关键字)的类
      • 抽象类不能被直接实例化。抽象类中只定义(或部分实现)子类需要的方法。子类可以通过继承抽象类并通过实现抽象类中的所有抽象方法,使抽象类具体化
      • 如果子类需要实例化,前提是它实现了抽象类中的所有抽象方法。如果子类没有全部实现抽象类中的所有抽象方法,那么该子类也是一个抽象类
      • 如果 B 实现了抽象方法 abstract_func() ,那么 B 中 abstract_func() 方法的访问控制不能比 A 中 abstract_func() 的访问控制更严格
    • 接口
      • 口则是纯粹的模版。接口只定义功能,而不包含实现的内容。接口用关键字 interface 来声明
      • interface 是完全抽象的,只能声明方法,而且只能声明 public 的方法,不能声明 private 及 protected 的方法,不能定义方法体,也不能声明实例变量 。然而, interface 却可以声明常量变量
      • 任何实现接口的类都要实现接口中所定义的所有方法
    • 相同点
      • 两者都是抽象类,都不能实例化
      • nterface 实现类及 abstract class 的子类都必须要实现已经声明的抽象方法
    • 不同点
      • interface 强调特定功能的实现,而 abstract class 强调所属关系
  • 数组

    • 交集 array_intersect
    • 并集 array_merge
    • 差集 array_diff
  • echo,print,print_r,var_dump

    • echo 和 print 的区别
      • 首先echo 和 print 都不是严格意义上的函数,他们都是 语言结构;他们都只能输出字符串,整型跟int型浮点型数据。不能打印复合型和资源型数据
      • echo 可以连续输出多个变量,而print只能一次输出一个变量
    • var_dump()和print_r()的区别
      • 两者都可以打印数组,对象之类的复合型变量
      • print_r() 只能打印一些易于理解的信息,且print_r()在打印数组时,会将把数组的指针移到最后边,使用 reset() 可让指针回到开始处。 而var_dump()不但能打印复合类型的数据,还能打印资源类型的变量。且var_dump()输出的信息则比较详细,一般调试时用得多
  • HTTP 状态码

    • 200 (成功) 服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页
    • 301 (永久移动) 请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置
    • 302 (临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求
    • 403 (禁止) 服务器拒绝请求
    • 404 (未找到) 服务器找不到请求的网页
    • 500 (服务器内部错误) 服务器遇到错误,无法完成请求
    • 502 (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应
    • 503 (服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态
    • 504 (网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求
  • redis connect和pconnect

    • connect:脚本结束之后连接就释放了
    • pconnect:脚本结束之后连接不释放,连接保持在php-fpm进程中。每个php-fpm进程占用一哥连接,当php-fpm进程结束时会释放掉 所以使用pconnect代替connect,可以减少频繁建立redis连接的消耗
    • 如果你的应用/服务, 可以有独立的进程, 使用自己的内存, 就可以放心地用 pconnect
  • ob缓存

    • ob_start() 开启缓存
    • ob_get_contents() 获取缓冲区的内容
    • ob_clean() 删除缓冲区的内容
    • ob_get_clean() 先获取然后再删除缓冲区内容
  • PHP7新特性

    • 类型的声明
    • set_exception_handler() 不再保证收到的一定是 Exception 对象
      • 很多致命错误以及可恢复的致命错误,都被转换为异常来处理了。 这些异常继承自 Error 类,此类实现了 Throwable 接口
    • 新增操作符“<=>”
    • 新增操作符“??”
    • define() 定义常量数组
    • 匿名函数
      $anonymous_func = function(){return 'function';};
      echo $anonymous_func(); // 输出function
      
    • 命名空间引用优化
  • 数组的实现

    • PHP使用HashTable来存储键-值对,但是又对HashTable进行了一些额外的设计来保证数组的有序,维护着K-V的一种对应关系,可以快速地根据键来检索到值,而且查找地时间复杂度为O(1)
      • key: 可以是数字也可以是字符串
      • value:目标数据
      • bucket:桶,hashtable地存储单元,一个用来存储k-v的容器
      • slot: 槽,一个slot可以拥有一个bucket或者多个
      • 当存在hash冲突的时候,PHP采用的是链地址法来解决,将同一个slot中的bucket通过链表连接起来
    • PHP中的hashtable的改进
    • 首先是再桶中新增h字段
    • 再把hash函数拆分为hash1和hash2
      • hash1:将key映射为h值
      • hash2:将h值映射为slot中的索引值
      • 拆分的目的
        • 将key可能为字符串也可能为数字的情况分开,桶中的h为数字的key,key为字符串的key
        • 用hash1生成的hash值(h)可以加快字符串key之间的比较速度,由于计算出来的hash值是不相同的,所以每次进行插入查找不用先检查key是否有重复,所以可以用来提高速度
    • 这样桶中的key全部都是字符串的key
  • 秒杀

    • mysql
      • 乐观锁
      • 悲观锁
    • redis
      • 单机
        • 锁 + descby
      • 集群
        • lua
    • rabbitmq
  • 红包

    • 随机生成10个数,求和,再求每个数的比例,再乘以红包总和就是每个红包的钱
    • 老婆:100块钱插9个板子,其实和上述是一个思路

其他

  • Nginx负载均衡实现,有几种方式

    • 轮询(默认)
      • 每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除
    • weight
      • 指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的 情况,权重越高,在被访问的概率越大
    • ip_hash
    • url_hash(第三方)
      • 按访问url的hash结果来分配请求,使每个url定向到同一个(对应的)后端服务器,后端服务器为缓存时比较有效
    • fair(第三方)
      • 按后端服务器的响应时间来分配请求,响应时间短的优先分配
  • 什么是 CGI?什么是 FastCGI?php-fpm,FastCGI,Nginx 之间是什么关系?

    • CGI:是公共网关接口 Web Server 与 Web Application之间数据交换的一种协议
    • FastCGI:FastCGI就像是一个常驻(long-live)型的CGI程序,它可以一直运行着。同 CGI,是一种通信协议,但比 CGI 在效率上做了一些优化,它是应用程序和WEB服务器连接的桥梁。Nginx并不能直接与 PHP-FPM 通信,而是将请求通过 FastCGI 交给 PHP-FPM 处理
    • PHP-FPM:是 PHP(Web Application)对 Web Server 提供的 FastCGI 协议的接口程序,额外还提供了相对智能一些任务管理
    • FastCGI 用来提高 cgi 程序性能,启动一个master,再启动多个 worker,不需要每次解析 php.ini. 而 php-fpm 实现了 FastCGI 协议,是 FastCGI 的进程管理器,支持平滑重启,可以启动的时候预先生成多个进程
      location ~ \.php$ {
          try_files $uri /index.php =404;
          fastcgi_pass 127.0.0.1:9000;
          fastcgi_index index.php;
          fastcgi_buffers 16 16k;
          fastcgi_buffer_size 32k;
          fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
          include fastcgi_params;
      }
      
  • 什么是 CSRF 攻击 ?XSS 攻击?如何防范?

    • CSRF,跨站请求伪造,攻击方伪装用户身份发送请求从而窃取信息或者破坏系统
      • 基本原理:用户访问A网站登陆并生成了cookie,再访问B网站,如果A网站存在CSRF漏洞,此时B网站给A网站的请求(此时相当于是用户访问),A网站会认为是用户发的请求,从而B网站就成功伪装了你的身份,因此叫跨站脚本攻击。
      • CSRF防范:
        • 合理规范api请求方式,GET,POST
        • 对POST请求加token令牌验证,生成一个随机码并存入session,表单中带上这个随机码,提交的时候服务端进行验证随机码是否相同。
    • XSS,跨站脚本攻击
      • 防范:不相信任何输入,过滤输入
  • explain索引类型

    • system 这是const连接类型的一种特例,表仅有一行满足条件
    • const 当确定最多只会有一行匹配的时候,MySQL优化器会在查询前读取它而且只读取一次,因此非常快。当主键放入where字句时,mysql把这个查询转为一个常量(高效)
    • eq_ref 最多只返回一条符合条件的记录。使用唯一性索引或主键查找时会发生(高效)
    • ref 一种索引访问,它返回所有匹配某个单个值得行。此类索引访问只有当使用非唯一性索引或唯一性索引非唯一性前缀索引时才会发生。 这个类型跟eq_ref不同的是,它用在关联操作只使用了索引的最左前缀,或者索引不是UNIQUE和PRIMARY KEY。ref可以用于使用=或<=>操作符的带索引的列。
    • range 范围扫描,一个有限制的索引扫描。key列显示使用了哪个索引。当使用=、<>、>、>=、<、<=、IS NULL、<=>、BETWEEN或者IN操作符,用常量比较关键字列时,可以使用range
    • index 和全表扫描一样。只是扫描表的时候按照索引次序进行而不是行。主要优点就是避免了排序,但是开销仍然非常大。 如在Extra列种看到Using index,说明正在使用覆盖索引,只扫描索引的数据,它比按索引次序全表扫描的开销要小很多
    • All 最坏的情况,全表扫描