php7字符串底层实现

本篇为《php7底层设计与源码实现》的读书笔记
php7 的字符串以zend_string 为载体,实现字符串的功能,还提供性能高效的smart_str

zend_string的结构体

struct  _zend_string{
  zend_refcounted_h gc;
  zend_ulong h;
  size_t len;
  char val[1];
}
  • gc 用作引用计数
  • h 哈希值,存储字符串对应的哈希值,方便在操作的时候,直接读取
  • len 存储字符串长度
  • val 柔性数组,存储字符串值的地址

h 和 len 体现了空间换时间的做法。

zend_string 的api

zend_string_init 将一个普通的字符串初始化成zend_string。
zend_string_extend 对字符串进行扩容。

  • 当扩容的字符串为普通字符串且refcount为1,直接调用perealloc进行扩容。
  • 扩容的字符串refcount大于1 或者 为内部字符串,则先申请一块内存,把值拷贝到申请的内存。对于普通字符串,还需要对老字符串把refcount 减1。

字符串的二进制安全

传统的c字符串,在取值的时候,在遇到'\0'的时候,默认遇到字符串结束了。而在php中,因为存储了字符串的长度,所以会根据字符串长度来取值,还原字符串的内容。不会因为字符串中含有'\0'而提前结束。因而可以在字符串中存储各种格式的数据。

smart_str

type_def struct{
  zend_string *s;
  size_t a;
} smart_str;

当对字符串内容需要频繁扩容的时候。php提供了一种新的结构来处理。
通过一次性申请足够大的空间,保证在修改字符串的时候,尽量不需要重新申请空间。一般如果字符串len <256 则申请256,如果len>256则申请大于len 且为4096的最小整数倍内存。通过空间换时间,避免每次修改都需要取申请或者释放内存

字符串的赋值与写时分离

zend_string中有refcount用来做计算。当字符串被引用的时候,则用zend_reference 来使在字符串内容不变的情况下,只保存一份zend_string。具体实现如下图


php7字符串底层实现_第1张图片
字符串赋值
php7字符串底层实现_第2张图片
字符串引用

字符串类型

几个概念

  • 字面量 代码中写死的变量值
  • 标识符 变量名、函数名、方法名、类名
  • php已知字符串 保留字
  • 保留字 无法用作函数名、类名等关键字 如 class public

php源码为了实现对字符串管理,对字符串进行分类。

  • IS_STR_PERSISTENT php的已知字符串,php代码中的字面量,标识符等字符串。开启opcache时,会常驻内存,如果未开启opcache则随着请求结束而被回收。
  • IS_STR_INTERNED 内部字符串

字符串类型转换

一般类型转换有两种隐式转换和显式转换
隐式转换由语言自身自动完成

  • 直接的变量赋值操作 当把字符串类型的数据赋予一个变量,不管之前这个变量的类型是什么,此时该变量就是一个字符串变量。
  • 运算式结果对变量的赋值操作 当表达式的操作数为同一数据类型,则只是改变表达式的结果,当表达式的操作数为不同数据类型,则会发生类型的自动转换。

显式类型转换
通过使用函数 或者是语言结构,完成对数据类型的转换。
如 (int) (float) 或者是 gettype settype函数

你可能感兴趣的:(php7字符串底层实现)