目录
深入理解PHP内核(一),深入理解php内核
首页 后端开发 php教程 深入理解PHP内核(一),深入理解php内核_PHP教程

深入理解PHP内核(一),深入理解php内核_PHP教程

Jul 12, 2016 am 09:05 AM
php 内核 深入理解 面向对象

深入理解PHP内核(一),深入理解php内核

PHP作为一门简单而强大的语言,能够提供很多Web适用的语言特性。从实践出发,继弱类型变量原理探究后,本文继续带领大家深入理解php内核。

 最近,和一个网友交流的时候,给我提了一个非常奇怪的问题。那就是,在一个运算中,加了一个引用之后,发现性能慢了一万倍。在我的脑海里面,引用是一个非常容易出错的问题,特别是PHP里面的引用,有非常多的陷阱。因为,以前专门研究过这一块PHP的源代码,所以,我可以比较清晰的解析引用到底是怎么一回事,希望,读了我这篇文章,能彻底理解这个问题。如果,有任何疑问,或者有一些你想了解的问题,可以给我留言。

先来看一段代码:

class RefferTest
{
 private $data;
 private $testKey;
 function __construct()
 {
  $key = "hello";
  $this->data[$key] = range(0, 10000);
  $this->testKey = $key;
 }
 function reffer($key)
 {
  $reffer = &$this->data[$key];
  return count($reffer);
 }
 function noreffer($key)
 {
  return count($this->data[$key]);
 }
 function test()
 {
  $t1 = microtime(true);
  for ($i = 0; $i < 5000; $i++)
  {
   $this->reffer($this->testKey);
  }
  $t2 = microtime(true) - $t1;
  var_dump("reffer: " . round($t2, 4));
  $t1 = microtime(true);
  for ($i = 0; $i < 5000; $i++)
  {
   $this->noreffer($this->testKey);
  }
  $t2 = microtime(true) - $t1;
  var_dump("noreffer: " . round($t2, 4));
 }
}
$test = new RefferTest();
$test->test();
登录后复制

如果你完这个代码,能说出,为了reffer 和 noreffer会差一万倍的性能,那下面的也就没有必要往下看了。这篇博客针对的是,PHP的新手。你可以运行一下这个代码试试看,的确差了一万倍。当然,那个网友遇到的问题的代码要比上面的复杂,上面的代码是我为了说明问题,特意简化的。或许你已经从代码里面看出问题了,但是,至于为什么会这样。我想,还是有必要分析一下。这样,以后,在使用PHP的时候,才不会犯相同的错误。

PHP为了减少复制,采用了一种copy on writer的机制。我想,这是一种非常常见的机制,你也一定听说过。比如,gcc 的 stl string 的实现,就是采用这样的机制,字符串赋值,不是真正的复制,而且,在修改的时候才会进行复制。我们先来举个最简单的例子:

 $a = str_repeat("", );
  $b = $a;
  $a[] = "";
登录后复制

$a 是一个非常大的字符串,如果 $b = $a 的时候,进行复制,那要耗费很多内存 和 cpu,这样非常的不划算,万一,下面的代码并不修改$a 和 $b 那复制根本没有必要。当然,$a 在后面又被修改了,这个时候,必须进行复制了,否则就不符合逻辑了。但是,现在问题来了,怎么知道,$a 在修改的时候,要进行复制呢,必须要有这样一个标记。方法就是采用引用计数。引用计数还被用来进行内存的管理。

基本的流程是这样的:

1: 创建一个变量,可以保存 10000 个 0 的这样一个字符串。

2: 创建一个变量符号 a ,这个变量符号引用 这个变量。注意,变量符号 和 变量不是一回事情,这两者是分离的。

如果从C语言的角度来说,PHP大概完成这样一件事情:

  char *varname = "a";
  size_t varname_len = strlen(varname);
  zend_hash_add(EG(active_symbol_table), varname, varname_len + , &var, sizeof(zval*), NULL);
登录后复制

active_symbol_table 是PHP的一个符号表,所有能访问到的变量都在这个里面,他是一个哈希表。var 这个变量,保存了 10000 个 0 这个字符串。而且是zval的结构,zval的结构如下:

typedef struct _zval_struct {
 zvalue_value value;
 zend_uint refcount;
 zend_uchar type;
 zend_uchar is_ref;
} zval;
typedef union _zvalue_value {
 long lval;
 double dval;
 struct {
  char *val;
  int len;
 } str;
 HashTable *ht;
 zend_object_value obj;
} zvalue_value;
登录后复制

zvalue_value 是一个联合,可以保存 long, double, 字符串,哈希表(PHP Array),还有就是 对象。也就是所有的PHP的类型。 zval 其实 就是 对 zvalue_value ,加入了类型type 和 引用is_ref,引用计数refcount三个功能。这就是PHP中的普通变量。要是用PHP做比较大型的东西,就会发现,内存占用非常厉害。就是因为,他一个变量 不是 传统C语言的那个变量了,它加了很多东西。

好了,第一句完成了,下面是第二句。第二句很简单,会产生一个新的变量符号b,把他加入 active_symbol_table ,但是不会增加新的一个变量,而只是,refcount++。赋值就完成了。如图:

首先我们要注意的是,a ,b 只是一个符号,他是active_symbol_table 表里面的一个key,都有一个指针指向一个zval,所以,a 和b 在 C语言层面上是完全一致的。我们就得出PHP变量第一定律:

PHP变量第一定律:如果两个变量指向同一个zval,那么这两个变量是无差别的。也就是说,任何对a 的操作 相对b 都是对称的。这里的对称,是这样理解的。就是镜子中的你,而不是等同。比如,对 a 进行 赋值,a 就会产生 copy。同样的,如果对b进行赋值,也会进行相同的操作,那就是b产生一个copy。也就是说,a 和b的行为是一样的。

第三句,当writer发生的时候,PHP会判断一下refcount 是否大于2,如果大于2,那么就复制一下zval,然后,把原来那个zval refcount--。这就是copy on writer 的全部了,你一定觉得,这一切你都是非常的熟悉,你都懂。

但是,PHP不仅仅是copy on writer 这样简单,它还有一个引用的问题。引入引用的概念,这样,问题就变的有些复杂了。因为,引用这个标记,意思就是说,writer 的时候,你也不需要复制。这样,会修改原来的那个变量。从我们在学校里面以前经常学习的哲学上来说,这是一对矛盾。他们是对立的,又是统一的,各有各的用处。所谓,存在的就是合理的。

好,下面我们来看看这对矛盾,我们只考虑两种组合的情况。多种组合都是类似的。两种组合的话,就是赋值在前,引用在后。

或者 引用在前,赋值在后。我们会分别讨论,先来看:就是赋值在前,引用在后的情况。

  $a = ;
   $b = $a;
   $c = &$a;
登录后复制

$b = $a, 是copy on writer 行为的 赋值。而 $c 和 $a 是引用赋值。我们假设在上面这样的情况下,我们可以用一个zval表示,也就是不需要复制,那么情况是这样的:

根据我们的PHP变量第一定律,那,就是说,a,b,c的操作是对称的,但是非常明显,对 b 操作要产生复制行为,而对a操作不会产生复制,操作行为不相同,和第一定律矛盾。也就是说,要使得上面的操作没有矛盾,必须,进行分离。分离的原则就是,谁制造矛盾,谁复制。显然是 第三句话,$c = &$a; 在制造矛盾。所以,内部变量的复制过程如下图:

上面情况是赋值在前,引用在后的情况。还有一种情况是,引用在前赋值在后:

 $a = ;
   $b = &$a;
   $c = $a;
登录后复制

按照PHP变量的第一定律,a,b,c 必须进行分离,才能保证定律的正确。可以发现,b 和 a 明显是一伙人,就是说,b 和 a 的操作是对称的,他们可以指向同一个zval ,而c 的行为和 a,b 不一样,改变c 需要进行复制。看到这里,我想,如果你看懂了的话,为什么刚开始,贴出来的那段代码的,那个两个count差异如此之大,你也应该明白了。当我和那个网友讨论的时候,它最后说,那这样的话,PHP设计的不好,我完全可以,$c先不进行复制,等c被write 了,再进行复制。看来要说懂一个东西,还是一件很难的事情,好好想想那个PHP第一定律吧。你可以假设不进行分离,c指向同一个zval,所以,c 和 a,b的行为是一样的,是is_ref = 1,所以,c 不会进行复制。最后一种内部执行情况可以用下图表示:

我以前也进行搞混这个引用,现在,你可以用那个第一定律来分析所有的情况了。PHP内核分析的文章,以后我还会写一些,如果你想深入了解PHP的某些方面,可以给我留言。

最后再补充一点,也是一个隐性的错误。

function count_bigarray()
{
 global $bigarray;
 return count($bigarray);
}
登录后复制

这里,没有显示的引用,但是这里隐藏了一个引用。PHP会自动创建一个引用全局变量 $bigarray 的代码,如果你在这里使用count,那么这个效率会非常的慢。最好直接通过$GLOBAL 数组进行引用。

下面文章将给大家介绍深入理解php内核二之SAPI探究,希望大家继续关注哦。

www.bkjia.comtruehttp://www.bkjia.com/PHPjc/1069346.htmlTechArticle深入理解PHP内核(一),深入理解php内核 PHP作为一门简单而强大的语言,能够提供很多Web适用的语言特性。从实践出发,继弱类型变量原理探...
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

<🎜>:泡泡胶模拟器无穷大 - 如何获取和使用皇家钥匙
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系统,解释
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆树的耳语 - 如何解锁抓钩
3 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

热门话题

Java教程
1675
14
CakePHP 教程
1429
52
Laravel 教程
1333
25
PHP教程
1278
29
C# 教程
1257
24
PHP与Python:了解差异 PHP与Python:了解差异 Apr 11, 2025 am 12:15 AM

PHP和Python各有优势,选择应基于项目需求。1.PHP适合web开发,语法简单,执行效率高。2.Python适用于数据科学和机器学习,语法简洁,库丰富。

PHP:网络开发的关键语言 PHP:网络开发的关键语言 Apr 13, 2025 am 12:08 AM

PHP是一种广泛应用于服务器端的脚本语言,特别适合web开发。1.PHP可以嵌入HTML,处理HTTP请求和响应,支持多种数据库。2.PHP用于生成动态网页内容,处理表单数据,访问数据库等,具有强大的社区支持和开源资源。3.PHP是解释型语言,执行过程包括词法分析、语法分析、编译和执行。4.PHP可以与MySQL结合用于用户注册系统等高级应用。5.调试PHP时,可使用error_reporting()和var_dump()等函数。6.优化PHP代码可通过缓存机制、优化数据库查询和使用内置函数。7

PHP和Python:比较两种流行的编程语言 PHP和Python:比较两种流行的编程语言 Apr 14, 2025 am 12:13 AM

PHP和Python各有优势,选择依据项目需求。1.PHP适合web开发,尤其快速开发和维护网站。2.Python适用于数据科学、机器学习和人工智能,语法简洁,适合初学者。

PHP行动:现实世界中的示例和应用程序 PHP行动:现实世界中的示例和应用程序 Apr 14, 2025 am 12:19 AM

PHP在电子商务、内容管理系统和API开发中广泛应用。1)电子商务:用于购物车功能和支付处理。2)内容管理系统:用于动态内容生成和用户管理。3)API开发:用于RESTfulAPI开发和API安全性。通过性能优化和最佳实践,PHP应用的效率和可维护性得以提升。

PHP的持久相关性:它还活着吗? PHP的持久相关性:它还活着吗? Apr 14, 2025 am 12:12 AM

PHP仍然具有活力,其在现代编程领域中依然占据重要地位。1)PHP的简单易学和强大社区支持使其在Web开发中广泛应用;2)其灵活性和稳定性使其在处理Web表单、数据库操作和文件处理等方面表现出色;3)PHP不断进化和优化,适用于初学者和经验丰富的开发者。

PHP和Python:解释了不同的范例 PHP和Python:解释了不同的范例 Apr 18, 2025 am 12:26 AM

PHP主要是过程式编程,但也支持面向对象编程(OOP);Python支持多种范式,包括OOP、函数式和过程式编程。PHP适合web开发,Python适用于多种应用,如数据分析和机器学习。

PHP和Python:代码示例和比较 PHP和Python:代码示例和比较 Apr 15, 2025 am 12:07 AM

PHP和Python各有优劣,选择取决于项目需求和个人偏好。1.PHP适合快速开发和维护大型Web应用。2.Python在数据科学和机器学习领域占据主导地位。

PHP与其他语言:比较 PHP与其他语言:比较 Apr 13, 2025 am 12:19 AM

PHP适合web开发,特别是在快速开发和处理动态内容方面表现出色,但不擅长数据科学和企业级应用。与Python相比,PHP在web开发中更具优势,但在数据科学领域不如Python;与Java相比,PHP在企业级应用中表现较差,但在web开发中更灵活;与JavaScript相比,PHP在后端开发中更简洁,但在前端开发中不如JavaScript。

See all articles