php实现弱语言底层原理分析(转)
php中弱语言类型的底层实现
PHP是弱语言类型,主要分为三类:
1、标量类型:integer、string、float、boolean
2、复合类型:array、object
3、特殊类型:resource、null
php是通过c语言进行实现,但是c语言为强类型,那php的弱语言类型是如何实现的呢。
1. 变量存储结构
变量的值存储到以下所示zval结构体中。 zval结构体定义在Zend/zend.h文件,其结构如下:
typedef struct _zval_struct zval;
...
struct _zval_struct {
/* Variable information */
zvalue_value value; /* value */
zend_uint refcount__gc;
zend_uchar type; /* active type */
zend_uchar is_ref__gc;
};
PHP使用这个结构来存储变量的所有数据。和其他编译性静态语言不同, PHP在存储变量时将PHP用户空间的变量类型也保存在同一个结构体中。这样我们就能通过这些信息获取到变量的类型。
zval结构体中有四个字段,其含义分别为:
属性名 | 含义 | 默认值 |
---|---|---|
refcount__gc | 表示引用计数 | 1 |
is_ref__gc | 表示是否为引用 | 0 |
value | 存储变量的值 | |
type | 变量具体的类型 |
2.变量类型:
zval结构体的type字段就是实现弱类型最关键的字段了,type的值可以为: IS_NULL、IS_BOOL、IS_LONG、IS_DOUBLE、IS_STRING、IS_ARRAY、IS_OBJECT和IS_RESOURCE 之一。 从字面上就很好理解,他们只是类型的唯一标示,根据类型的不同将不同的值存储到value字段。 除此之外,和他们定义在一起的类型还有IS_CONSTANT和IS_CONSTANT_ARRAY。
这和我们设计数据库时的做法类似,为了避免重复设计类似的表,使用一个标示字段来记录不同类型的数据。
二.变量的值存储
前面提到变量的值存储在zvalue_value联合体中,结构体定义如下:
typedef union _zvalue_value {
long lval; /* long value */
double dval; /* double value */
struct {
char *val;
int len;
} str;
HashTable *ht; /* hash table value */
zend_object_value obj;
} zvalue_value;
这里使用联合体而不是用结构体是出于空间利用率的考虑,因为一个变量同时只能属于一种类型。 如果使用结构体的话将会不必要的浪费空间,而PHP中的所有逻辑都围绕变量来进行的,这样的话, 内存浪费将是十分大的。这种做法成本小但收益非常大。
各种类型的数据会使用不同的方法来进行变量值的存储,其对应赋值方式如下:
- 一般类型
变量类型 | 宏 | |
---|---|---|
boolean | ZVAL_BOOL | 布尔型/整型的变量值存储于(zval).value.lval中,其类型也会以相应的IS_*进行存储。
Z_TYPE_P(z)=IS_BOOL/LONG; Z_LVAL_P(z)=((b)!=0); |
integer | ZVAL_LONG | |
float | ZVAL_DOUBLE | |
null | ZVAL_NULL | NULL值的变量值不需要存储,只需要把(zval).type标为IS_NULL。
Z_TYPE_P(z)=IS_NULL; |
resource | ZVAL_RESOURCE | 资源类型的存储与其他一般变量无异,但其初始化及存取实现则不同。
Z_TYPE_P(z) = IS_RESOURCE; Z_LVAL_P(z) = l; |
- 字符串String
字符串的类型标示和其他数据类型一样,不过在存储字符串时多了一个字符串长度的字段。
struct {
char *val;
int len;
} str;
C中字符串是以\0结尾的字符数组,这里多存储了字符串的长度,这和我们在设计数据库时增加的冗余字段异曲同工。 因为要实时获取到字符串的长度的时间复杂度是O(n),而字符串的操作在PHP中是非常频繁的,这样能避免重复计算字符串的长度, 这能节省大量的时间,是空间换时间的做法。
这么看在PHP中strlen()函数可以在常数时间内获取到字符串的长度。 计算机语言中字符串的操作都非常之多,所以大部分高级语言中都会存储字符串的长度。
- 数组Array
数组是PHP中最常用,也是最强大变量类型,它可以存储其他类型的数据,而且提供各种内置操作函数。数组的存储相对于其他变量要复杂一些, 数组的值存储在zvalue_value.ht字段中,它是一个HashTable类型的数据。 PHP的数组使用哈希表来存储关联数据。哈希表是一种高效的键值对存储结构。PHP的哈希表实现中使用了两个数据结构HashTable和Bucket。 PHP所有的工作都由哈希表实现,在下节HashTable中将进行哈希表基本概念的介绍以及PHP的哈希表实现。
- 对象Object
在面向对象语言中,我们能自己定义自己需要的数据类型,包括类的属性,方法等数据。而对象则是类的一个具体实现。 对象有自身的状态和所能完成的操作。
PHP的对象是一种复合型的数据,使用一种zend_object_value的结构体来存放。其定义如下:
typedef struct _zend_object_value {
zend_object_handle handle; // unsigned int类型,EG(objects_store).object_buckets的索引
zend_object_handlers *handlers;
} zend_object_value;
PHP的对象只有在运行时才会被创建,前面的章节介绍了EG宏,这是一个全局结构体用于保存在运行时的数据。 其中就包括了用来保存所有被创建的对象的对象池,EG(objects_store),而object对象值内容的zend_object_handle域就是当前 对象在对象池中所在的索引,handlers字段则是将对象进行操作时的处理函数保存起来。 这个结构体及对象相关的类的结构_zend_class_entry,将在第五章作详细介绍。
PHP的弱变量容器的实现方式是兼容并包的形式体现,针对每种类型的变量都有其对应的标记和存储空间。 使用强类型的语言在效率上通常会比弱类型高,因为很多信息能在运行之前就能确定,这也能帮助排除程序错误。 而这带来的问题是编写代码相对会受制约。
php实现弱语言底层原理分析(转)的更多相关文章
- HashMap底层原理分析(put、get方法)
1.HashMap底层原理分析(put.get方法) HashMap底层是通过数组加链表的结构来实现的.HashMap通过计算key的hashCode来计算hash值,只要hashCode一样,那ha ...
- springAop:Aop(Xml)配置,Aop注解配置,spring_Aop综合案例,Aop底层原理分析
知识点梳理 课堂讲义 0)回顾Spring体系结构 Spring的两个核心:IoC和AOP 1)AOP简介 1.1)OOP开发思路 OOP规定程序开发以类为模型,一切围绕对象进行,OOP中完成某个任务 ...
- JMM和Volatile底层原理分析
JMM和volatile分析 1.JMM:Java Memory Model,java线程内存模型 JMM:它是一个抽象的概念,描述的是线程和内存间的通信,java线程内存模型和CPU缓存模型类似,它 ...
- Activiti工作流学习笔记(三)——自动生成28张数据库表的底层原理分析
原创/朱季谦 我接触工作流引擎Activiti已有两年之久,但一直都只限于熟悉其各类API的使用,对底层的实现,则存在较大的盲区. Activiti这个开源框架在设计上,其实存在不少值得学习和思考的地 ...
- 从Redis分布式缓存实战入手到底层原理分析、面面俱到覆盖大厂面试考点
概述 官方说明 Redis官网 https://redis.io/ 最新版本6.2.6 Redis中文官网 http://www.redis.cn/ 不过中文官网的同步更新维护相对要滞后不少时间,但对 ...
- AQS底层原理分析
J.U.C 简介 Java.util.concurrent 是在并发编程中比较常用的工具类,里面包含很多用来在并发场景中使用的组件.比如线程池.阻塞队列.计时器.同步器.并发集合等等.并发包的作者是大 ...
- 基于JAVA Socket的底层原理分析及工具实现
前言 在工作开始之前,我们先来了解一下Socket 所谓Socket,又被称作套接字,它是一个抽象层,简单来说就是存在于不同平台(os)的公共接口.学过网络的同学可以把它理解为基于传输TCP/IP协议 ...
- 多线程(四) AQS底层原理分析
J.U.C 简介 Java.util.concurrent 是在并发编程中比较常用的工具类,里面包含很多用来在并发 场景中使用的组件.比如线程池.阻塞队列.计时器.同步器.并发集合等等.并 发包的作者 ...
- vue-双向响应数据底层原理分析
总所周知,vue的一个大特色就是实现了双向数据响应,数据改变,视图中引用该数据的部分也会自动更新 一.双向数据绑定基本思路 “数据改变,视图中引用该数据的部分也会自动更新“,从这句话,我们可以分析出以 ...
随机推荐
- docker 安装nginx、php-fpm
运行环境: 创建目录: mkdir -p /Users/sui/docker/nginx/conf.d && mkdir /Users/sui/www && cd /U ...
- 你还有没有印象?腾讯QQ16个版本界面你认识多少?
腾讯公司成立于1998年11月11日(马化腾也曾经戏称“腾讯公司的生日被马云弄成双11购物节了”).1997年,马化腾接触到了ICQ:1998年11月11日,马化腾和同学张志东在广东省深圳市注册成立“ ...
- Oracle Linux下载教程(以Oracle Linux 6.9为例)
一.说明 Oracle Linux是Oracle基于Redhat,针对Oracle系列软件(尤其是Oracle数据库)进行优化后的Linux发行版. 虽然Oracle Linux下载是免费的,但是并不 ...
- AI工具(矩形工具)(椭圆工具的操作与矩形类似)(剪切蒙版)5.11
矩形工具:按住SHIFT键,可以绘制一个正方形. 按住ALT键,可以绘制以落点为中心的矩形. 同时按住SHIFT和ALT键可以绘制以鼠标落点为中心的正方形. 选择矩形工具,点击页面,输入高宽,精确绘制 ...
- vue组件通信方式总结
对于vue来说,组件之间的消息传递是非常重要的,下面是我对组件之间消息传递的各种方式的总结,总共有8种方式. 1. props和$emit 父组件向子组件传递数据是通过prop传递的,子组件传递数据给 ...
- Java反射《二》获取构造器
package com.study.reflect; import java.lang.reflect.Constructor; import java.lang.reflect.Invocation ...
- http协议与浏览器缓存
http协议与浏览器缓存 F5刷新与在地址栏回车的区别 链接
- 【转载】OpenCV 摄像头控制
参考:[OpenCV] -- 简单摄像头操作 - 代码人生 - 博客频道 - CSDN.NET http://blog.csdn.net/qiurisuixiang/article/details/8 ...
- 哈希表概念和实现,C/C++实现
body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...
- oracle数据导入导出数据与编码格式不正确
1.导入dmp文件 imp ZHCG/ZHCG@ORCL file=E:\20160902.1007.dmp full=y 2.导出数据 exp system/manager@ORCL file ...