PHP7内核之Reference详解

问题

上一章说过引用(REFERENCE)在PHP5的时候是一个标志位, 而在PHP7以后我们把它变成了一种新的类型:IS_REFERNCE. 然而引用是一种很常见的应用, 所以这个变化带来了很多的变化, 也给我们在做PHP7开发的时候, 因为有的时候疏忽忘了处理这个类型, 而带来不少的bug.

最简单的情况, 就是在处理各种类型的时候, 从此以后我们要多考虑这种新的类型, 比如在PHP7中, 这样的代码形式就变得很常见了:

try_again:
swtich (Z_TYPE_P(zv)) {
   case IS_TRING:
   break;
   case IS_ARRAY:
   break;
  ...
   case IS_REFERENCE:
   zv = Z_REFVAL_P(zv); //解引用
   goto try_again;
   break;
}

如果大家自己写的扩展, 如果忘了考虑这种新的类型, 那么就会导致问题.

为什么?
那么既然这种新类型会带来这么多问题, 那么当时为什么要用把引用变成一种类型呢? 为什么不还是使用一个标志位呢?

一句话来说, 就是我们不得不这么做. -_#

前面说到, Hashtable直接存储的是zval, 这样在符号表中, 俩个zval如何共用一个数值呢? 对于字符串等复杂类型来说还好, 我们貌似可以在zend_refcounted结构中加入一个标志位来表明是引用来解决, 然而这个也会遇到Change On Write带来的复制, 但是我们知道在PHP7中, 一些类型是直接存储在zval中的, 比如IS_LONG, 但是引用类型是需要引用计数的, 那么对于一个是IS_LONG并且又是IS_REFERNCE的zval该如何表示呢?

为此, 我们创造了这个新的类型:

如图所示, 引用是一种新的类型:zend_reference, 对于IS_REFERNCE类型的zval, zval.value.ref是一个指向zend_reference的指针, 它包含了引用计数和一个zval, 具体的zval的值是存在zval.value.ref->val中的.

所以对于IS_LONG的引用来说, 就用一个类型是IS_REFERNCE的zval, 它指向一个zend_reference, 而这个zend_reference->val中是一个类型为IS_LONG的zval.

Change On Write
PHP采用引用计数来做简单的垃圾回收, 考虑如下的代码:

<?php
1. $val = "laruence";
2. $ref = &$val;
3. $copy = $val;
?>

$ref和$val是指向同一个zval的引用, 在PHP5的时候, 我们是通过一个引用计数为2, 并且引用标志位为1来表示这种情况, 当把$val复制给$copy(line 3)的时候, 我们发现$val是一个计数大于1的引用, 所以要产生Change on write, 也就是分离. 所以我们需要复制这个zval.

而在PHP7中, 情况就变得简单了很多, 首先在引用赋值给$ref(line 2)的时候, 生成一个IS_REFERNCE类型, 然后因为此时有俩个变量引用它所以zend_reference这个结构的引用计数zval.value.ref->gc.refcount为2.

再随后的赋值给$copy(line 3)的时候, 发现$val是一个引用, 于是让$copy指向的是zval.value.ref->val, 也就是字符串值为laruence的zval, 然后把zval的引用计数+1, 也就是zval.value.ref->val.value.str.gc.refcount为2. 并没有产生复制.

从而这就很好的解决了上一章所说的PHP5的那个经典的问题, 比如我们在PHP7下运行上一章的那个问题, 我们得到的结果是:

$ php-7.0/sapi/cli/php /tmp/1.php
Used 0.00021380008539
Used 0.00020173048281

可见确实没有发生复制, 从而不会产生任何的性能问题.

以上所述是小编给大家介绍的PHP7内核之Reference详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • 什么是PHP7中的孤儿进程与僵尸进程

    基本概念 我们知道在unix/linux中,正常情况下,子进程是通过父进程创建的,子进程在创建新的进程.子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束. 当一个 进程完成它的工作终止之后,它的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止状态. 孤儿进程 一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程.孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作. 僵尸进程 一

  • PHP7匿名类的用法示例

    本文实例讲述了PHP7匿名类的用法.分享给大家供大家参考,具体如下: <?php /** * Created by PhpStorm. * User: Itboot * Date: 2019/1/17 * Time: 18:15 */ class An { private $num; protected $age = 15; public function __construct() { $this->num = 1; } protected function bar(): int { ret

  • Linux下 php7安装redis的方法

    安装redis服务 1 下载redis cd /usr/local/ 进入安装目录 wget http://download.redis.io/redis-stable.tar.gz 2 解压安装 tar xvzf redis-stable.tar.gz cd redis-stable make && make install 3 配置redis 拷贝配置文件到/etc/redis/redis.conf cp redis.conf /etc/redis/6379redis.conf vim

  • Centos7.4环境安装lamp-php7.0教程

    本文实例讲述了Centos7.4环境安装lamp-php7.0的方法.分享给大家供大家参考,具体如下: 一. 环境准备 桥接模式 能访问外网 #ping www.baidu.com ping得通则能到外网 关闭防火墙 #systemctl disable firewalld //禁用防火墙 #systemctl stop firewalld //关闭防火墙 关闭seLinux #vim /etc/selinux/config 改为: SELINUX=disabled 配置yum源 # cd /e

  • PHP7 echo和print语句实例用法

    在 PHP 中,有两种基本的输出方法:echo 和 print. 在本教程中,我们几乎在每个例子中都会用到 echo 和 print.因此,本节为您讲解更多关于这两条输出语句的知识. PHP echo 和 print 语句 echo 和 print 之间的差异: echo - 能够输出一个以上的字符串 print - 只能输出一个字符串,并始终返回 1 提示:echo 比 print 稍快,因为它不返回任何值. PHP echo 语句 echo 是一个语言结构,有无括号均可使用:echo 或 e

  • docker自定义镜像构建php7的方法

    首先进行简单的docker安装. 要进行自定义镜像,我们需要选择一个基础镜像进行构建自己的镜像:其实说白了,就是在一个有基础定义好的容器内,执行安装各种程序的命令,生成 所谓的Dockerfile 文件,既然如此第一步我们首先需要找一个本地的镜像作为基础镜像来操作即可: 1 如上图所示,我们来以centos为基础镜像,来构建一个Dockerfile 2第二步我们需要构建一个目录,用于存放Dockerfile文件 在root下构建docker_demo目录,存放 Dockerfile文件以及需要安

  • centos7上编译安装php7以php-fpm方式连接apache

    好几个月之间其实已经配置过LAMP LNMP等等一些配置,以前配置都是按照晚上抄的,基本都能配置出来,现重头学想自己配置下,但是发现好多配置都忘了 ,中间踩了几个坑,记录下,也更彻底的学习下..... ./configure --prefix=/usr/local/php7 --enable-fpm 以fpm模式安装,这个还可以改成 --with-apxs2=PATH模式,两者只能取其一 --enable-so --with-config-file-path=/etc 只能配置文件位置 --wi

  • 为Plesk PHP7启用Oracle OCI8扩展方法总结

    注:本文适用于RHEL/CentOS发行版. 步骤1.安装构建自定义PHP 7模块所需的devel包 # yum install plesk-php70-devel gcc glibc-devel libmemcached-devel zlib-devel make libaio.x86_64 步骤2.下载oracle-instantclient12.1-basic-12.1.0.2.0-1.x86_64.rpm和oracle-instantclient12.1-devel-12.1.0.2.0

  • PHP7引入的"??"和"?:"的区别讲解

    实践出真知- 测试代码 输入测试: <?php $array = [ 'a' => 1, 'b' => 2, 'c' => [], ]; $a = $array['c'] ?? 0; $b = $array['c'] ?: 0; $c = $array['d'] ?? 0; $d = $array['d'] ?: 0; $e = $array['c'] ? 1 : 0; $f = isset($array['c']) ? 1 : 0; $g = $array['d'] ? 1 :

  • PHP7内核之Reference详解

    问题 上一章说过引用(REFERENCE)在PHP5的时候是一个标志位, 而在PHP7以后我们把它变成了一种新的类型:IS_REFERNCE. 然而引用是一种很常见的应用, 所以这个变化带来了很多的变化, 也给我们在做PHP7开发的时候, 因为有的时候疏忽忘了处理这个类型, 而带来不少的bug. 最简单的情况, 就是在处理各种类型的时候, 从此以后我们要多考虑这种新的类型, 比如在PHP7中, 这样的代码形式就变得很常见了: try_again: swtich (Z_TYPE_P(zv)) {

  • Linux中的内核链表实例详解

    Linux中的内核链表实例详解 链表中一般都要进行初始化.插入.删除.显示.释放链表,寻找节点这几个操作,下面我对这几个操作进行简单的介绍,因为我的能力不足,可能有些东西理解的不够深入,造成一定的错误,请各位博友指出. A.Linux内核链表中的几个主要函数(下面是内核中的源码拿出来给大家分析一下) 1)初始化: #define INIT_LIST_HEAD(ptr) do { \ (ptr)->next = (ptr); (ptr)->prev = (ptr); \ } while (0)

  • Centos7 Yum安装PHP7.2流程教程详解

    Centos7Yum安装PHP7.2 1.安装源 安装php72w,是需要配置额外的yum源地址的,否则会报错不能找到相关软件包. php高版本的yum源地址,有两部分,其中一部分是epel-release,另外一部分来自webtatic.如果跳过epel-release的话,安装webtatic的时候,会有错误爆出. 所以,这里需要的命令是: rpm -Uvh https://dl.fedoraproject.org/pub/epel/7/x86_64/Packages/e/epel-rele

  • CentOS7编译安装php7.1的教程详解

    1.首先安装依赖包: yum install libxml2 libxml2-devel openssl openssl-devel bzip2 bzip2-devel libcurl libcurl-devel libjpeg libjpeg-devel libpng libpng-devel freetype freetype-devel gmp gmp-devel libmcrypt libmcrypt-devel readline readline-devel libxslt libxs

  • Linux内核启动参数详解

    1.环境: Ubuntu 16.04 Linux linuxidc 4.4.0-89-generic #112-Ubuntu SMP Mon Jul 31 19:38:41 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux 2.查看当前linux内核的启动参数: cat /proc/cmdline 笔者的输出内容如下: BOOT_IMAGE=/boot/vmlinuz-4.4.0-89-generic root=UUID=bef418fa-4202-4513-b39

  • Java 中 Reference用法详解

    Java  Reference详解 在 jdk 1.2 及其以后,引入了强引用.软引用.弱引用.虚引用这四个概念.网上很多关于这四个概念的解释,但大多是概念性的泛泛而谈,今天我结合着代码分析了一下,首先我们先来看定义与大概解释(引用类型在包 Java.lang.ref 里). 1.强引用(StrongReference) 强引用不会被GC回收,并且在java.lang.ref里也没有实际的对应类型.举个例子来说: Object obj = new Object(); 这里的obj引用便是一个强引

  • linux下用户程序同内核通信详解(netlink机制)

    简介 linux下用户程序同内核通信的方式一般有ioctl, proc文件系统,剩下一个就是Netlink套接字了. 这里先介绍下netlink. Netlink 是一种在内核与用户应用间进行双向数据传输的非常好的方式,用户态应用使用标准的 socket API 就可以使用 netlink 提供的强大功能,内核态需要使用专门的内核 API 来使用 netlink. Netlink 相对于系统调用,ioctl 以及 /proc 文件系统而言具有以下优点: 1,为了使用 netlink,用户仅需要在

  • PHP7扩展开发之基于函数方式使用lib库的方法详解

    本文实例讲述了PHP7扩展开发之基于函数方式使用lib库的方法.分享给大家供大家参考,具体如下: 前言 首先说下什么是lib库.lib库就是一个提供特定功能的一个文件.可以把它看成是PHP的一个文件,这个文件提供一些函数方法.只是这个lib库是用c或者c++写的. 使用lib库的场景.一些软件已经提供了lib库,我们就没必要再重复实现一次.如,原先的mysql扩展,就是使用mysql官方的lib库进行的封装. 在本文,我们将建立一个简单的lib库,并在扩展中进行封装调用. 代码 基础代码 这个扩

  • PHP7如何开启Opcode打造强悍性能详解

    前言 鸟哥在博客中说,提高PHP 7性能的几个tips,第一条就是开启opcache: 记得启用Zend Opcache, 因为PHP7即使不启用Opcache速度也比PHP-5.6启用了Opcache快, 所以之前测试时期就发生了有人一直没有启用Opcache的事情 那么什么是Opcache呢? Opcache 的前生是 Optimizer+ ,它是PHP的官方公司 Zend 开发的一款闭源但可以免费使用的 PHP 优化加速组件. Optimizer+ 将PHP代码预编译生成的脚本文件 Opc

  • CentOS7+apache+php7+mysql5.7配置教程详解

    yum upgrade yum install net-tools 安装apache 关闭SELinux 编辑器打开 etc/selinux/config 文件,找到 SELINUX=enforcing 字段,将其改成 SELINUX=disabled ,并重启设备. yum -y install httpd mod_ssl 配置防火墙 firewall-cmd --permanent --add-port=80/tcp firewall-cmd --permanent --add-port=4

随机推荐