Skip to the content.

PHP

问题

PHP 内存管理

  1. 内存预分配: PHP 会预先向系统申请一大块内存, 然后由此分配一块内存给到申请者, 避免了频繁的系统调用.
  2. HashTable 在初始化时只会预先给一小块内存, 在存入取出大量数据时, 会引起内存的分配和释放.
  3. 垃圾回收(GC): refcount 减少到了0, 直接当垃圾回收; refcount 减少, 但没有到0, 会加入缓冲区链表中, 当缓冲区到达阈值时, PHP 会调用方法遍历链表, 发现是垃圾就清理.

程序内存溢出怎么查

PHP 底层实现, 运行过程?

执行过程: PHP 代码 => Token => 抽象语法树 => Opcodes => 执行 具体步骤:

Token 是 PHP 代码被分割成有意义的标识. PHP7 一共有 137 种 Token, 在 zend_language_parser.h 文件中做了定义.

Token 就是一个个词块, 但是单独的词块不能表达完整的语义. 所以需要语法分析器根据语法匹配 Token, 将 Token 进行串联. 语法分析器串联完 Token 后的产物就是抽象语法树

PHP 如何实现多线程?

PHP 语言特点? 与java最大区别?

PHP如何实现并发?

如何保证client端代码安全?

画抽象语法树

为什么 PHP7 要抽象语法树

  1. 运行时间上的优化
  2. 语义上的优化

empty 作用

判断变量是否为空, 比如说 null, false, 0, ‘’, [] , ‘0’ , 未设置的值

协程实现原理, 处理网络连接有什么优势

在用户线程中模拟操作系统线程并进行调度, 一个协程 A 调用网络写请求 write 后, 然后调用 yield 将控制权交出, 协程调度器从所有协程中获取满足唤醒条件 协程, 对其调用 resume, 使该协程继续执行.

在网络连接的处理中, 相对于线程来看优势在于, 减少了上下文切换的额外消耗, 简化了并发程序的复杂度

协程相对于多线程优点

  1. 协程的执行效率很高, 因为子程序切换不是线程切换, 而是由程序自身控制, 因此没有线程切换的开销, 和多线程相比, 线程数越多, 协程的性能优势就越明显.
  2. 不需要多线程的锁机制, 因为只有一个线程, 也不存在同时写变量冲突, 在协程中控制共享资源不加锁, 只需要判断状态, 所以执行效率比线程高很多.

协程如何利用多核 CPU

使用多进程+协程

PHP下有无实现多路复用的方法?

到多路复用是一个发展进步的过程, 这个发展过程为:

PHP 有哪些与并发 IO 编程相关的扩展

PHP 优缺点

PHP 数组的实现

PHP 中数组实际上是一个有序映射, 映射是一种把 values 关联到 keys 的类型.

在 PHP 中, 这种映射关系是使用 散列表(HashTable) 实现的. HashTable 通过 映射函数 将一个 String Key 转换为一个普通的数字下标, 并将对应的 Value 值储存到下标对应的数组元素中.

使用两次散列, 确定在映射表的位置, 映射表的值储存数组元素的下标, 哈希表是无序的, 为了实现数组的有序, 所以采用了 映射表 + 数组元素的结构.

PHP解析整体流程? 如何进行性能优化?

传值和引用的区别

include 和 require 的区别

都是导入一个文件, include 导入失败会报错, require 导入失败会报警告

PHP是否适合做守护进程,为什么(内存管理这一块)

现在来看已经能够胜任作为守护进程了, PHP 在内存管理这一块,

PHP的垃圾回收机制

变量分为两个部分: 变量名(zval), 变量值(zend_value). PHP 中使用引用计数来做 GC 的, 当一个变量值的 refcount 减少到0时会直接被回收, 减少但是没有到0就会加入垃圾缓冲区链表中, 缓冲区到达阈值后启动检查函数, 是垃圾的会在这个时候被回收掉.

PHP7 新特性

类在实例化的时候, 发生了什么

从底层来看, 实例化一个对象分为三步

  1. 根据类名去全局类列表内查找该类是否存在, 如果存在, 则获取存储类的变量
  2. 判断类是否为普通类(非抽象类或接口); 如果是普通类则给需要创建你的对象存放的 zend_value 容器分配内存, 并设置容器类型为 IS_OBJECT
  3. 执行对象初始化操作, 将对象添加到对象列表(对象池)中

获取和设置类成员变量的底层

&&和&的差别

&& 是逻辑与运算 & 是位与运算

无限递归会造成哪个区域的错误?

发生内存溢出错误: Fatal error: Allowed memory size of 536870912 bytes exhausted (tried to allocate 262144 bytes) in

函数栈溢出

子类构造的时候,整个构造的过程

为什么选择PHP

go 协程和 swoole 协程什么区别

协程是轻量级的线程, 开销很小

cli 模式下的几个生命周期

php-fpm 运行机制?(master 管理,worker 循环 accept)

阻塞的单线程模型, 单 master, 多 worker 结构, 同一个 worker 进程同时只能处理一个请求.

PHP-FPM 是 fast-cgi 的实现, 提供了进程管理的功能, 包含 master, worker 两种进程:

php-fpm 模式下,kill -9 master-pid,会怎么样?kill matser-pid 呢?(信号机制)

kill 命令默认使用 15 (SIGTERM), kill master-pid 会立即让 master 关闭, 会影响到当前请求

kill -9 master-pid (SIGKILL), 有OS来执行杀死进程的操作, 优先级最高, 会影响到当前请求

内存分配流程?为什么要这么设计?

预先申请一块内存在 PHP 内部管理, 应用在申请内存时, 会从这一部分进行申请, 释放时也是先释放回到内存管理中. 这样设计话可以避免小内存的申请释放对操作系统上的额外性能的消耗.

GC 的出现是为了解决什么问题?什么时候会触发 GC?说下大概流程

PHP 通常用在 PHP-fpm 中, 单个 worker 进程需要处理多个请求才会被关闭, 这种情形下如果没有垃圾回收机制可能会在一次次请求中内存逐渐被占满, 会造成内存泄漏.

zval 中的 zend_refcount 计数减少时, 如果等于0直接会被回收, 大于0时会被加入到缓冲区链表中, 当缓冲区大小到达阈值时, 会执行垃圾回收程序.

php 里的数组是怎么实现的?(这里要注意下 php5 和 php7 实现的区别,优化了非常多)

nginx 和 php-fpm 的通信机制?fast-cgi 和 cgi 区别?

Nginx 接收到请求会给 worker 进程处理, worker 通过 fast-cgi 模块转发给 php-fpm 处理, php-fpm 中的 worker 会使用 poll 模型, 直接触发可读事件, 空闲 worker 中的第一个会来处理这个请求. 也就是说, php-fpm 的 master 不会参与分配请求.

fast-cgi 和 CGI 都是后台语言的交互协议, fast-cgi 有性能上的优化.

php-fpm 创建 worker 进程的规则是什么?不同场景下怎么选择?

php 和 mysql 的通信机制?长链接和短链接啥区别?怎么实现的?连接池要怎么实现?

  1. TCP/IP: 通过网络访问
  2. socket: 本地通过 socket 文件访问

短链接在客户端结束时连接就断开了, 而长连接会被 PHP-FPM 用来复用. 减少了数据库连接的开销时间.

独立服务多进程持有一组数据库连接, 应用的数据库请求将在连接池服务中进行转发. 每次发送会查询空闲的数据库连接进行使用, 通常的话包含初始创建连接数, 动态控制空闲进程数数量的功能.

依赖注入是什么?如何实现的?能解决什么问题?(代码层面不再依赖具体实现,解耦)

指服务依赖的其他服务不通过服务自己创建的方式, 而是由外部传入的方式. 通常来说使用反射实现的. 解决了服务模块之间的解耦效果, 编写代码时不用考虑外部服务的具体实现, 只需要依据接口来使用服务即可. 最常见的例子就是缓存服务的注入, 使用缓存服务的服务不需要关注缓存服务的具体实现, 不论是 文件缓存, Redis 缓存, 内存缓存, 数据库缓存等.

PHP 合并数组的几种方式及比较