PHP面试问题整理一(PHP + MySQL + Redis + mongoDB + kafka)

2021-04-16 16:05:06

PHP 

    面向对象的理解


       面向对象的思想,既把一系列事物可以抽象看作一个个体,或者一种类型的属性,操作看作是一个对象,将其封装为一个类,

  内部包含这个抽象概念相关的一些属性及相关操作


     面向对象的三大特征

 

        封装,继承,多态


      封装:既把一系列的属性,方法封装在一个类中,给每个属性添加关键字(public,protected,private)

                修饰可以使得这些属性不能被外部轻易访问。

        private:只能类内部访问操作。

        protect:受保护类型,用于本类及子类调用

        public: 可以内部调用,实例调用,子类调用


       __construct():实例化类对象的时候调用,当子类继承父类,子类实例化对象时会默认先调用子类的构造函数,

                  如果希望调用父类的构造函数,则需要在子类的构造函数中通过parent::__construct();

                 访问父类的构造方法,注意此处的关键字parent为小写,同时如果需要访问父类的方法,也可以采用parent关键字访问

                  parent::父类方法名(或者采用父类名::方法名)

       继承:通过extends关键字可以继承父类的一些属性

      多态:多态性是指相同的操作或函数、过程可作用于多种类型的对象上并获得不同的结果。


   PHP8新特点

       JIT的新特性,则是将PHP代码转化为传统的机器码,而并非通过zend虚拟机来运行,这大大增加了运行速度。但是缺点是向下不兼容。

      

      match表达式 是PHP8中新增的关键字(即无法再做类名),其作用与switch有点相似,用于变量的值转换与赋值

      $input = true;

      $result = match($input) {

"true",true  => 1, //可多值匹配,匹配方式为===,无匹配值会抛出Fatal error

"false"      => 0,

"null"       => NULL,

        };

       var_dump($result); //输出: int(1)


  Attributes即注解,它提供了一种向类添加元数据的方法,无需解析文档块.符号为#[],

  使用格式为#[param('value1','value2')],可定义多个也可写成数组形式


    联合类型Union Types

    Union Types 支持声明并接收多个不同类型的值,它是两种或多种类型的集合,使用时可以选择其一


    static 返回类型

  虽然已经可以返回 self,但是考虑到 PHP 具有动态类型的性质,PHP 8 中支持 static 返回类型将更加高效


   弱映射WeakMap

  WeakMap弱映射的一般用例是将数据与单个对象实例关联起来,而不强制它们保持活动状态,从而在长时间运行的进程中有效地泄漏内存。

  例如,可以使用弱映射来记录计算结果


 框架

  Laravel 框架的底层运行原理 参考(https://segmentfault.com/a/1190000038587591)

   

     1、Laravel 框架的入口文件 index.php,引入自动加载 autoload.php 文件


     2、创建应用实例,并同时完成了(基本绑定($this、容器类Container等等)、基本服务提供者的注册(Event、log、routing)、

         核心类别名的注册(比如db、auth、config、router等))


    3、开始 Http 请求的处理


         make 方法从容器中解析指定的值为实际的类,比如 $app->make(Illuminate\Contracts\Http\Kernel::class); 解析出来 App\Http\Kernel 


          handle 方法对 http 请求进行处理


          实际上是 handle 中 sendRequestThroughRouter 处理 http 的请求


       首先,将 request 绑定到共享实例


       然后执行 bootstarp 方法,运行给定的引导类数组 $bootstrappers,这里是重点,包括了加载配置文件、环境变量、服务提供者、门面、异常处理、引导提供者等


     之后,进入管道模式,经过中间件的处理过滤后,再进行用户请求的分发


    在请求分发时,首先,查找与给定请求匹配的路由,然后执行 runRoute 方法,实际处理请求的时候 runRoute 中的 runRouteWithinStack 


    最后,经过 runRouteWithinStack 中的 run 方法,将请求分配到实际的控制器中,执行闭包或者方法,并得到响应结果


4、 将处理结果返回


框架比较 参考 (https://blog.csdn.net/chenrui310/article/details/100104939)

    一、ThinkPHP


ThinkPHP(FCS)是一个轻量级的中型框架,是从Java的Struts结构移植过来的中文PHP开发框架。它使用面向对象的开发结构和MVC模式,并且模拟实现了Struts的标签库,各方面都比较人性化,熟悉J2EE的开发人员相对比较容易上手,适合php框架初学者。 ThinkPHP的宗旨是简化开发、提高效率、易于扩展,其在对数据库的支持方面已经包括MySQL、MSSQL、Sqlite、PgSQL、 Oracle,以及PDO的支持。ThinkPHP有着丰富的文档和示例,框架的兼容性较强,但是其功能有限,因此更适合用于中小项目的开发。


优点


1.借助成熟的Java思想

2.易于上手,有丰富的中文文档;学习成本低,社区活跃度高

3.框架的兼容性较强,PHP4和PHP5完全兼容、完全支持UTF8等。

4.适合用于中小项目的开发

5.从thinkphp3.2.2引入composer包管理工具


缺点


1.对Ajax的支持不是很好;

2.目录结构混乱,相比其他框架目录结构要差一点;

3.上手容易,但是深入学习较难。



二、Yii


Yii 是一个基于组件的高性能php框架,用于开发大型Web应用。Yii采用严格的OOP编写,并有着完善的库引用以及全面的教程。从 MVC,DAO/ActiveRecord,widgets,caching,等级式RBAC,Web服务,到主题化,I18N和L10N,Yii提供了 今日Web 2.0应用开发所需要的几乎一切功能。事实上,Yii是最有效率的PHP框架之一。


优点


1.纯OOP

2.用于大规模Web应用

3.模型使用方便

4.开发速度快,运行速度也快。性能优异且功能丰富

5.使用命令行工具。

6.支持composer包管理工具


缺点:


1.对Model层的指导和考虑较少

2.文档实例较少

3.英文太多

4.要求PHP技术精通,OOP编程要熟练!

5.View并不是理想view,理想中的view可能只是html代码,不会涉及PHP代码。


三、laravel


优点

1.laravel的设计思想是很先进的,非常适合应用各种开发模式TDD, DDD 和BDD

2.支持composer包管理工具

3.集合了php 比较新的特性,以及各种各样的设计模式,Ioc 容器,依赖注入、门面、契约。测试功能等。



缺点

1.基于组件式的框架,所以比较臃肿


四、CodeIgniter


优点:


1.Code Igniter推崇“简单就是美”这一原则。没有花哨的设计模式、没有华丽的对象结构,一切都是那么简单。几行代码就能开始运行,再加几 行代码就可以进行输出。可谓是“大道至简”的典范。 

2.配置简单,全部的配置使用PHP脚本来配置,执行效率高;

3.具有基本的路由功能,能够进行一定程度的路由;

4.具有初步的Layout功能,能够制作一定程度的界面外观;

5.数据库层封装的不错,具有基本的MVC功能. 

6.快速简洁,代码不多,执行性能高,

7.框架简单,容易上手,学习成本低,文档详细;

8.自带了很多简单好用的library,框架适合小型应用.


缺点:


1.本身的实现不太理想。

2.内部结构过于混乱,虽然简单易用,但缺乏扩展能力。

3.把Model层简单的理解为数据库操作. 

4.框架略显简单,只能够满足小型应用,略微不太能够满足中型应用需要.


MySQL  


    mysql-innodb锁类型(数据库锁定机制就是为了保证数据的一致性,使得各种共享资源在被并发访问时变得有序。)


    1.表级锁定(table-level)


      表级锁是mysql中锁粒度最大的锁定机制,一次会将整张表锁定,不会出现死锁问题


    2.行级锁定(row-level)


   行级锁是锁粒度最小的锁定机制。由于锁粒度最小,所以锁定资源发生的争用也就最小,这样提高了应用程序并发处理的能力同时提高了整个系统的性能,但是每次获取锁和释放锁都要做很多事情,带来的消耗也就增加,也最容易发生死锁。


  3.页级锁定(page-level)


   页级锁定的特点是锁定颗粒度介于行级锁定与表级锁之间,所以获取锁定所需要的资源开销,以及所能提供的并发处理能力也同样


   是介于上面二者之间。另外,页级锁定和行级锁定一样,会发生死锁。


 mysql这三种锁的特性可以大致归纳如下: 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低;


 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高;    


 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。


  innodb存储引擎与myisam最大的不同就是:innodb支持事务;采用行级锁



MyISAM 和 InnoDB的适用场景

MyISAM适合:(1)做很多count 的计算;(2)插入不频繁,查询非常频繁;(3)没有事务。


InnoDB适合:(1)可靠性要求比较高,或者要求事务;(2)表更新和查询都相当的频繁,并且表锁定的机会比较大的情况。


 

MyISAM 和 InnoDB的区别

1)MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持


2)mysiam表不支持外键


3)在执行数据库写入的操作(insert,update,delete)的时候,mysiam表会锁表,而innodb表会锁行


4)当你的数据库有大量的写入、更新操作而查询比较少或者数据完整性要求比较高的时候就选择innodb表。当你的数据库主要以查询为主,相比较而言更新和写 入比较少,并且业务方面数据完整性要求不那么严格,就选择mysiam表。因为mysiam表的查询操作效率和速度都比innodb要快

    


mysql的索引分为单列索引(全文索引,主键索引,唯一索引,普通索引)和组合索引。


单列索引:一个索引只包含一个列,一个表可以有多个单列索引。


组合索引:一个组合索引包含两个或两个以上的列,

假设字段a,b都有索引,我们的查询条件是a=1,b=2查询过程是mysql会先挑选出符合a=1的结果集,再在这些结果集中挑选b=2的结果集,但是mysql并不会在查询a,b时都用到索引,只会用其中一个,这和我们的预期不一样,所以,我们要使用组合索引


索引失效的情况 


 1.如果条件中有or,即使其中有条件带索引也不会使用(这也是为什么尽量少用or的原因)


  要想使用or,又想让索引生效,只能将or条件中的每个列都加上索引


  2.使用查询的时候遵循mysql组合索引的"最左前缀"规则,假设现在有组合索引(a,b,c),查询语句就只能是a=1或a=1

        and b=1或a=1 and b=1 and c=1。这里有两点需要注意①a=1 and b=1和b=1 and a=1一样,没有区别,都会使用索引

        ②组合索引(a,b,c)的最左前缀是a;组合索引(c,b,a)的最左前缀是c,最左前缀和表字段顺序无关

        在组合索引中,如果where查询条件中某个列使用了范围查询(不管%在哪),则其右边的所有列都无法使用索引优化查询


  3.like查询以%开头


  4.如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引


  5.如果mysql估计使用全表扫描要比使用索引快,则不使用索引


        6.索引列不能是表达式的一部分,也不能作为函数的参数,否则无法使用索引查询。下面是例子:


            SELECT * FROM user_test WHERE user_name = concat(user_name, 'fei');


     MySQL Explain 

     我们会有时会开慢查询去记录一些执行时间比较久的SQL语句,找出这些SQL语句并不意味着完事了,

     些时我们常常用到explain这个命令来查看一个这些SQL语句的执行计划,查看该SQL语句有没有使用上了索引,有没有做全表扫描,这都可以通过explain命令来查看

     

    MySQL 参考(https://www.cnblogs.com/williamjie/p/11081592.html)




  redis  


  redis的数据结构(value): String,list,set,orderset,hash


   应用场景:

   String : 1存储json类型对象,2计数器,3优酷视频点赞等

   list(双向链表) 1可以使用redis的list模拟队列,堆,栈 2朋友圈点赞(一条朋友圈内容语句,若干点赞语句)

    hash(hashmap) 1保存对象 2分组

   

    3 string与hash的数据差别


     在网路传输时候,必须要进行进行序列化,才可以进行网路传输,那么在使用string类型的类型的时候需要进行相关序列化,

     hash也是要进行相关的系列化,所以会存在很多序列化,在存储的时候hash是可以存储的更加丰富,但是在反序列化的时候,

     string的反序列化相对较低,而hash的序列化和返序列化是相对hash类更加复杂,所以看业务场景,如果是数据经常修改的那种,

     为了性能可以使用string,如果是数据不是经常改的那种就可以使用hash,由于hash,存储数据时比较丰富,可以存储多种数据类型


  redis的持久化方式: 将内存中的数据异步写入硬盘中,两种方式:RDB(默认)和AOF

  RDB持久化原理:通过bgsave命令触发,然后父进程执行fork操作创建子进程,子进程创建RDB文件,根据父进程内存生成临时快照文件,完成后对原有文件进行原子替换(定时一次性将所有数据进行快照生成一份副本存储在硬盘中)


优点:是一个紧凑压缩的二进制文件,Redis加载RDB恢复数据远远快于AOF的方式。


缺点:由于每次生成RDB开销较大,非实时持久化,


AOF持久化原理:开启后,Redis每执行一个修改数据的命令,都会把这个命令添加到AOF文件中。


优点:实时持久化。


缺点:所以AOF文件体积逐渐变大,需要定期执行重写操作来降低文件体积,加载慢



缓存击穿的解决方案:


  原因:就是别人请求数据的时候,很多数据在缓存中无法查询到,直接进入数据查询,


  解决方法,对相关数据进行查询的数据只查询缓存,如果是一些特殊的可以进行数据库查询,


  也可以采用布隆过滤器进行查询



缓存雪崩的解决方案:


  缓存雪崩的原因:一次性加入缓存的数据过多,导致内存过高,从而影响内存的使用导致服务宕机


  解决方法:


  1 redis集群,通过集群方式将数据放置


  2 后端服务降级和限流:当一个接口请求次数过多,那么就会添加过多数据,可以对服务进行限流,限制访问的数量,这样就可以减少问题的出现

   


其他


  一、关系型数据库-MySQL

1、在不同的引擎上有不同的存储方式。

2、查询语句是使用传统的sql语句,拥有较为成熟的体系,成熟度很高。

3、开源数据库的份额在不断增加,mysql的份额页在持续增长。

4、缺点就是在海量数据处理的时候效率会显著变慢。


二、非关系型数据库-MongoDB

非关系型数据库(nosql ),属于文档型数据库。先解释一下文档的数据库,即可以存放xml、json、bson类型系那个的数据。这些数据具备自述性,呈现分层的树状数据结构。数据结构由键值(key=>value)对组成。


1、存储方式:虚拟内存+持久化。

2、查询语句:是独特的MongoDB的查询方式。

3、适合场景:事件的记录,内容管理或者博客平台等等。

4、架构特点:可以通过副本集,以及分片来实现高可用。

5、数据处理:数据是存储在硬盘上的,只不过需要经常读取的数据会被加载到内存中,将数据存储在物理内存中,从而达到高速读写。

6、成熟度与广泛度:新兴数据库,成熟度较低,Nosql数据库中最为接近关系型数据库,比较完善的DB之一,适用人群不断在增长。


三、MongoDB优势与劣势

优势:

1、在适量级的内存的MongoDB的性能是非常迅速的,它将热数据存储在物理内存中,使得热数据的读写变得十分快。

2、MongoDB的高可用和集群架构拥有十分高的扩展性。

3、在副本集中,当主库遇到问题,无法继续提供服务的时候,副本集将选举一个新的主库继续提供服务。

4、MongoDB的Bson和JSon格式的数据十分适合文档格式的存储与查询。

劣势:

1、 不支持事务操作。MongoDB本身没有自带事务机制,若需要在MongoDB中实现事务机制,需通过一个额外的表,从逻辑上自行实现事务。

2、 应用经验少,由于NoSQL兴起时间短,应用经验相比关系型数据库较少。

3、MongoDB占用空间过大。


 Kafka  参考(https://blog.csdn.net/qq_28900249/article/details/90346599)

Kafka是分布式发布-订阅消息系统,它最初是由LinkedIn公司开发的,之后成为Apache项目的一部分,

Kafka是一个分布式,可划分的,冗余备份的持久性的日志服务,它主要用于处理流式数据。


缓冲和削峰:上游数据时有突发流量,下游可能扛不住,或者下游没有足够多的机器来保证冗余,kafka在中间可以起到一个缓冲的作用,把消息暂存在kafka中,下游服务就可以按照自己的节奏进行慢慢处理。


解耦和扩展性:项目开始的时候,并不能确定具体需求。消息队列可以作为一个接口层,解耦重要的业务流程。只需要遵守约定,针对数据编程即可获取扩展能力。


冗余:可以采用一对多的方式,一个生产者发布消息,可以被多个订阅topic的服务消费到,供多个毫无关联的业务使用。


健壮性:消息队列可以堆积请求,所以消费端业务即使短时间死掉,也不会影响主要业务的正常进行。


异步通信:很多时候,用户不想也不需要立即处理消息。消息队列提供了异步处理机制,允许用户把一个消息放入队列,但并不立即处理它。想向队列中放入多少消息就放多少,然后在需要的时候再去处理它们。



一、Kafka的优势如下:


       高吞吐量、低延迟:kafka每秒可以处理几十万条消息,它的延迟最低只有几毫秒;


       可扩展性:kafka集群支持热扩展;


       持久性、可靠性:消息被持久化到本地磁盘,并且支持数据备份防止数据丢失;


       容错性:允许集群中节点故障(若副本数量为n,则允许n-1个节点故障);


       高并发:支持数千个客户端同时读写。


二、Kafka适合以下应用场景:


       日志收集:一个公司可以用Kafka可以收集各种服务的log,通过kafka以统一接口服务的方式开放给各种consumer;


       消息系统:解耦生产者和消费者、缓存消息等;


        用户活动跟踪:kafka经常被用来记录web用户或者app用户的各种活动,如浏览网页、搜索、点击等活动,这些活动信息被各个服务器发布到kafka的topic中,然后消费者通过订阅这些topic来做实时的监控分析,亦可保存到数据库;


       运营指标:kafka也经常用来记录运营监控数据。包括收集各种分布式应用的数据,生产各种操作的集中反馈,比如报警和报告;


       流式处理:比如spark streaming和storm。