面试题-PHP

PHP数组底层实现原理

1、底层实现是通过散列表(hash table) + 双向链表(解决hash冲突)

  • hashtable:将不同的关键字(key)通过映射函数计算得到散列值(Bucket->h) 从而直接索引到对应的Bucket
  • hash表保存当前循环的指针,所以foreach 比for更快
  • Bucket:保存数组元素的key和value,以及散列值h

2、如何保证有序性

  • 1. 散列函数和元素数组(Bucket)中间添加一层大小和存储元素数组相同的映射表。
  • 2. 用于存储元素在实际存储数组中的下标
  • 3. 元素按照映射表的先后顺序插入实际存储数组中
  • 4. 映射表只是原理上的思路,实际上并不会有实际的映射表,而是初始化的时候分配Bucket内存的同时,还会分配相同数量的 uint32_t 大小的空间,然后将 arData 偏移到存储元素数组的位置。

3、解决hash重复(php使用的链表法):

  • 1. 链表法:不同关键字指向同一个单元时,使用链表保存关键字(遍历链表匹配key)
  • 2. 开放寻址法:当关键字指向已经存在数据的单元的时候,继续寻找其他单元,直到找到可用单元(占用其他单元位置,更容易出现hash冲突,性能下降)

4、基础知识

  • 链表:队列、栈、双向链表、
  • 链表 :元素 + 指向下一元素的指针
  • 双向链表:指向上一元素的指针 + 元素 + 指向下一元素的指针

502 的原因及解决方法

原因:nginx将请求提交给网关(php-fpm)处理异常导致

1)fastcgi 缓冲区设置过小

fastcgi_buffers 8 16k;

fastcgi_buffer_size 32k;

2)php-cgi的进程数设置过少

查看FastCgi进程数:netstat -anpo | grep “php-cgi”| wc -l

调整参数最大子进程数:max_children

一般按照单个进程20M计算需要需要设置的子进程数

3)max_requests(内存溢出或频繁重启)

参数指明每个children最多能处理的请求数量,到达最大值之后会重启children。

设置过小可能导致频繁重启children:

php将请求轮询给每个children,在大流量的场景下,每一个children 到达最大值的时间差不多,如果设置过小可能多个children 在同一时间关闭,nginx无法将请求转发给php-fpm,cpu降低,负载变高。

设置过大可能导致内存泄露

4)php执行时间超过nginx等待时间

fastcgi_connect_timeout

fastcgi_send_timeout

fastcgi_read_timeout

5)fastcgi执行时间

max_execution_time

 

php-fpm 详解及生命周期

1、基础知识

1)CGI协议

  • 动态语言的代码文件需要通过对应的解析器才能被服务器识别
  • CGI协议就是用来使服务器和解释器相互通信的
  • 服务器解析PHP文件需要PHP解释器加上对应的CGI协议

2)CGI程序 = php-cgi

  • php-cgi就是一个遵守CGI协议的CGI程序
  • 同时也就是PHP解释器
  • 标准的CGI每个请求都会解析php.ini,初始化执行环境等,降低性能
  • 每次修改配置之后需要重新php-cgi才能让php.ini生效
  • 不能动态worker调度,只能一开始指定数量的worker

3)FastCGI协议

  • 和CGI一样也是一个协议/规范,不过是再CGI的基础上优化,效率更高
  • 用来提高CGI程序性能的
  • 实现了CGI进程的管理

4)FastCGI程序 = php-fpm

  • php-fpm就是一个遵守FastCGI协议的FastCGI程序
  • FastCGI程序对CGI程序的管理模式
    • 启动一个master进程,解析配置文件,初始化环境
    • 启动多个worker子进程
    • 接受到请求之后,传递给woker进程去执行
  • 解决修改php.ini之后平滑重启问题
    • process_control_timeout:子进程接受主进程复用信号的超时时间(在规定时间内处理完请求,完成不了就不管了)
    • 设定php-fpm留给fastcgi进程响应重启信号的时间
    • process_control_timeout = 0,也就是不生效,无法保证平滑重启
    • process_control_timeout设置过大可能导致系统请求堵塞
    • process_control_timeout =10的情况下,如果代码逻辑需要11s,重启旧可能导致代码执行部分退出
    • 建议值:request_terminate_timeout
  • 重启类型
    • 优雅重启
    • 强制重启

Nginx 和 php 之间的通信

1、通信方式:fastcgi_pass

1)tcp socket

  • 跨服务器,nginx和php不在一个机器时,只能用这个方式
  • 面向连接的协议,更好的保证通信的正确性和完整性

2)unix socket

  • 不需要网络协议栈、打包拆包等
  • 减少tcp 开销,效率比tcp socket 更高
  • 高并发时候不稳定,连接数暴增产生大量的长时缓存,大数据包可能直接返回异常

web 漏洞及问题

1、sql注入

2、XSS攻击

跨站脚本攻击。它指的是恶意攻击者往 Web 页面里插入恶意 html 代码,当用户浏览该页之时,嵌入的恶意 html 代码会被执行,从而达到恶意用户的特殊 目的。XSS 属于被动式的攻击,因为其被动且不好利用,所以许多人常呼略其危害性。但是随着前端技术的不断进步富客户端的应用越来越多,这方面的问题越来 越受关注。举个简单例子 : 假如你现在是 sns 站点上一个用户,发布信息的功能存在漏洞可以执行 js 你在 此刻输入一个 恶意脚本,那么当前所有看到你新信息的人的浏览器都会执行这个脚本弹出提示框 (很爽吧 弹出广告 :)),如果你做一些更为激进行为呢 后果难以想象。

3、CSRF攻击

跨站点伪造请求。顾名思义就是 通过伪造连接请求在用户不知情的情况下,让用户以自己的身份来完成攻击者需要达到的一些目的。csrf 的攻击不同于 xss csrf 需要被攻击者的主动行为触发。这样听来似乎是有 “被钓鱼” 的嫌疑。

4、文件上传漏洞

5、跨域问题:

1)jsonp

2)cors

3)nginx代理

OOP是什么?

答:oop是面向对象编程,面向对象编程是一种计算机编程架构,OOP 的一条基本原则是计算机程序是由单个能够起到子程序作用的单元或对象组合而成。

OOP具有三大特点

1、封装性:也称为信息隐藏,就是将一个类的使用和实现分开,只保留部分接口和方法与外部联系,或者说只公开了一些供开发人员使用的方法。于是开发人员只 需要关注这个类如何使用,而不用去关心其具体的实现过程,这样就能实现MVC分工合作,也能有效避免程序间相互依赖,实现代码模块间松藕合。

2、继承性:就是子类自动继承其父级类中的属性和方法,并可以添加新的属性和方法或者对部分属性和方法进行重写。继承增加了代码的可重用性。PHP只支持单继承,也就是说一个子类只能有一个父类。

3、多态性:子类继承了来自父级类中的属性和方法,并对其中部分方法进行重写。于是多个子类中虽然都具有同一个方法,但是这些子类实例化的对象调用这些相同的方法后却可以获得完全不同的结果,这种技术就是多态性。多态性增强了软件的灵活性。

1、易维护

采用面向对象思想设计的结构,可读性高,由于继承的存在,即使改变需求,那么维护也只是在局部模块,所以维护起来是非常方便和较低成本的。

2、质量高

在设计时,可重用现有的,在以前的项目的领域中已被测试过的类使系统满足业务需求并具有较高的质量。

3、效率高

在软件开发时,根据设计的需要对现实世界的事物进行抽象,产生类。使用这样的方法解决问题,接近于日常生活和自然的思考方式,势必提高软件开发的效率和质量。

4、易扩展

由于继承、封装、多态的特性,自然设计出高内聚、低耦合的系统结构,使得系统更灵活、更容易扩展,而且成本较低。

 

 

接口和抽象类的区别是什么?

答:抽象类是一种不能被实例化的类,只能作为其他类的父类来使用。抽象类是通过关键字abstract来声明的。

抽象类与普通类相似,都包含成员变量和成员方法,两者的区别在于,抽象类中至少要包含一个抽象方法,抽象方法没有方法体,该方法天生就是要被子类重写的。

抽象方法的格式为:abstract function abstractMethod();

接口是通过 interface 关键字来声明的,接口中的成员常量和方法都是 public 的,方法可以不写关键字public,接口中的方法也是没有方法体。接口中的方法也天生就是要被子类实现的。

抽象类和接口实现的功能十分相似,最大的不同是接口能实现多继承。在应用中选择抽象类还是接口要看具体实现。

子类继承抽象类使用 extends,子类实现接口使用implements。

PHP的垃圾收集机制是怎样的?

PHP可以自动进行内存管理,清除不再需要的对象。

PHP使用了引用计数(reference counting)这种单纯的垃圾回收(garbage collection)机制。每个对象都内含一个引用计数器,每个reference连接到对象,计数器加1。当reference离开生存空间或被设为NULL,计数器减1。当某个对象的引用计数器为零时,PHP知道你将不再需要使用这个对象,释放其所占的内存空间。