仓酷云

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 1773|回复: 19
打印 上一主题 下一主题

[学习教程] PHP教程之PHP内核引见及扩大开辟指南―基本常识

[复制链接]
乐观 该用户已被删除
跳转到指定楼层
楼主
发表于 2015-2-16 00:23:12 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
学会了生成静态网页,现在你应该接触一下XML了,恩,XML也了解了,那么AJAX你也得接触接触吧?AJAX完了....然后...      1、 基本常识
  本章扼要引见一些Zend引擎的外部机制,这些常识和Extensions亲切相干,同时也能够匡助咱们写出加倍高效的PHP代码。
  1.1 PHP变量的存储
  1.1.1 zval布局
  Zend利用zval布局来存储PHP变量的值,该布局以下所示:
  1. 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;  struct _zval_struct {     /* Variable information */     zvalue_value value;     /* value */     zend_uint refcount;     zend_uchar type;            /* active type */     zend_uchar is_ref; };  typedef struct _zval_struct zval; <span id="more-597"></span>Zend依据
    type值来决意
    会见
    value的哪一个
    成员,可用值以下
复制代码
  IS_NULLN/A
  IS_LONG对应value.lval
  IS_DOUBLE对应value.dval
  IS_STRING对应value.str
  IS_ARRAY对应value.ht
  IS_OBJECT对应value.obj
  IS_BOOL对应value.lval.
  IS_RESOURCE对应value.lval
  依据这个表格可以发明两个成心思的中央:起首是PHP的数组其实就是一个HashTable,这就注释了为何PHP可以撑持联系关系数组了;其次,Resource就是一个long值,它外面寄存的凡是是个指针、一个外部数组的index或其它甚么只要创立者本人才晓得的器材,可以将其视作一个handle
  1.1.1 援用计数
  援用计数在渣滓搜集、内存池和字符串等中央使用普遍,Zend就完成了典范的援用计数。多个PHP变量可以经由过程援用计数机制来同享统一份zval,zval中残剩的两个成员is_ref和refcount就用来撑持这类同享。
  很分明,refcount用于计数,当增减援用时,这个值也响应的递增和递加,一旦减到零,Zend就会收受接管该zval。
  那末is_ref呢?
  1.1.2 zval形态
  在PHP中,变量有两种——援用和非援用的,它们在Zend中都是采取援用计数的体例存储的。关于非援用型变量,请求变量间互不相关,修正一个变量时,不克不及影响到其他变量,采取Copy-On-Write机制便可处理这类抵触——当试图写入一个变量时,Zend若发明该变量指向的zval被多个变量同享,则为其复制一份refcount为1的zval,并递加原zval的refcount,这个进程称为“zval分别”。但是,关于援用型变量,其请求和非援用型相反,援用赋值的变量间必需是绑缚的,修正一个变量就修正了一切绑缚变量。
  可见,有需要指出以后zval的形态,以分离应对这两种情形,is_ref就是这个目标,它指出了以后一切指向该zval的变量是不是是采取援用赋值的——要末满是援用,要末全不是。此时再修正一个变量,只要当发明其zval的is_ref为0,即非援用时,Zend才会履行Copy-On-Write。
  1.1.3 zval形态切换
  当在一个zval长进行的一切赋值操作都是援用或都长短援用时,一个is_ref就足够敷衍了。但是,世界总不会那末夸姣,PHP没法对用户停止这类限制,当咱们夹杂利用援用和非援用赋值时,就必需要停止出格处置了。
  情形I、看以下PHP代码:
  1. <!--p $a = 1;  $b = &$a;  $c = &$b;  $d = $c;  // 在一堆援用
    赋值中,拔出
    一个非援用
    -->
复制代码
  全进程以下所示:
  这段代码的前三句将把a、b和c指向一个zval,其is_ref=1, refcount=3;第四句是个非援用赋值,凡是情形下只需求增添援用计数便可,但是方针zval属于援用变量,纯真的增添援用计数明显是毛病的, Zend的处理举措是为d独自生成一份zval正本。
  全进程以下所示:
  

  1.1.1 参数传递
  PHP函数参数的传递和变量赋值是一样的,非援用传递相当于非援用赋值,援用传递相当于援用赋值,而且也有能够会招致履行zval形态切换。这在前面还将提到。
  1.2 HashTable布局
  HashTable是Zend引擎中最主要、利用最普遍的数据布局,它被用来存储几近一切的器材。
  1.1.1 数据布局
  HashTable数据布局界说以下:
  1. typedef struct bucket {     ulong h;                // 寄存
    hash     uint nKeyLength;     void *pData;            // 指向value,是用户数据的正本
         void *pDataPtr;     struct bucket *pListNext;   // pListNext和pListLast构成
         struct bucket *pListLast;   // 全部
    HashTable的双链表     struct bucket *pNext;       // pNext和pLast用于构成
    某个hash对应     struct bucket *pLast;       // 的双链表     char arKey[1];              // key } Bucket;  typedef struct _hashtable {     uint nTableSize;     uint nTableMask;     uint nNumOfElements;     ulong nNextFreeElement;     Bucket *pInternalPointer;   /* Used for element traversal */     Bucket *pListHead;     Bucket *pListTail;     Bucket **arBuckets;         // hash数组     dtor_func_t pDestructor;    // HashTable初始化时指定,烧毁
    Bucket时挪用
         zend_bool persistent;       // 是不是
    采取
    C的内存分派
    例程     unsigned char nApplyCount;     zend_bool bApplyProtection; #if ZEND_DEBUG     int inconsistent; #endif } HashTable;
复制代码
  总的来讲,Zend的HashTable是一种链表散列,同时也为线性遍历停止了优化,图示以下:
  


  HashTable中包括两种数据布局,一个链表散列和一个双向链表,前者用于停止疾速键-值查询,后者便利线性遍历和排序,一个Bucket同时存在于这两个数据布局中。
  关于该数据布局的几点注释:
  l 链表散列中为何利用双向链表?
  普通的链表散列只需求按key停止操作,只需求单链表就够了。然而,Zend有时需求从链表散列中删除给定的Bucket,利用双链表可以十分高效的完成。
  l nTableMask是干甚么的?
  这个值用于hash值到arBuckets数组下标的转换。现在始化一个HashTable,Zend起首为arBuckets数组分派nTableSize巨细的内存,nTableSize取不小于用户指定巨细的最小的2^n,即二进制的10*。nTableMask = nTableSize C 1,即二进制的01*,此时h & nTableMask就刚好落在 [0, nTableSize C 1] 里,Zend就以其为index来会见arBuckets数组。
  l pDataPtr是干甚么的?
  凡是情形下,当用户拔出一个键值对时,Zend会将value复制一份,并将pData指向value正本。复制操作需求挪用Zend外部例程 emalloc来分派内存,这是个十分耗时的操作,而且会损耗比value大的一块内存(多出的内存用于寄存cookie),假如value很小的话,将会形成较大的华侈。思索到HashTable多用于寄存指针值,因而Zend引入pDataPtr,当value小到和指针一样长时,Zend就直接将其复制到pDataPtr里,而且将pData指向pDataPtr。这就防止了emalloc操作,同时也有益于进步Cache射中率。
  arKey巨细为何只要1?为何不利用指针办理key?
  arKey是寄存key的数组,但其巨细却只要1,其实不足以放下key。在HashTable的初始化函数里可以找到以下代码:
  1p = (Bucket *) pemalloc(sizeof(Bucket) - 1 + nKeyLength, ht->persistent);
  可见,Zend为一个Bucket分派了一块足够放下本人和key的内存,
  l 上半局部是Bucket,下半局部是key,而arKey“刚好”是Bucket的最初一个元素,因而就能够利用arKey来会见key了。这类手段在内存办理例程中最为罕见,当分派内存时,实践上是分派了比指定巨细要大的内存,多出的上半局部凡是被称为cookie,它存储了这块内存的信息,好比块巨细、上一块指针、下一块指针等,百度的Transmit法式就利用了这类办法。
  不必指针办理key,是为了削减一次emalloc操作,同时也能够进步Cache射中率。另外一个必须的来由是,key绝大局部情形下是固定不变的,不会由于key变长了而招致从头分派全部Bucket。这同时也注释了为何不把value也一同作为数组分派了――由于value是可变的。
  1.2.2 PHP数组
  关于HashTable还有一个疑问没有回覆,就是nNextFreeElement是干甚么的?
  分歧于普通的散列,Zend的HashTable答应用户直接指定hash值,而疏忽key,乃至可以不指定key(此时,nKeyLength为0)。同时,HashTable也撑持append操作,用户连hash值也不必指定,只需求供应value,此时,Zend就用nNextFreeElement作为hash,以后将nNextFreeElement递增。
  HashTable的这类行动看起来很奇异,由于这将没法按key会见value,已完整不是个散列了。了解成绩的关头在于,PHP数组就是利用HashTable完成的――联系关系数组利用正常的k-v映照将元素到场HashTable,其key为用户指定的字符串;非联系关系数组则直接利用数组下标作为hash值,不存在key;而当在一个数组中夹杂利用联系关系和非联系关系时,或利用array_push操作时,就需求用nNextFreeElement了。
  再来看value,PHP数组的value直接利用了zval这个通用布局,pData指向的是zval*,依照上一节的引见,这个zval*将直接存储在pDataPtr里。因为直接利用了zval,数组的元素可所以恣意PHP类型。
  数组的遍历操作,即foreach、each等,是经由过程HashTable的双向链表来停止的,pInternalPointer作为游标志录了以后地位。
  1.2.3 变量符号表
  除数组,HashTable还被用来存储很多其他数据,好比,PHP函数、变量符号、加载的模块、类成员等。
  一个变量符号表就相当于一个联系关系数组,其key是变量名(可见,利用很长的变量名并非个好主张),value是zval*。
  在任一时辰PHP代码都可以看见两个变量符号表――symbol_table和active_symbol_table――前者用于存储全局变量,称为全局符号表;后者是个指针,指向以后举动的变量符号表,凡是情形下就是全局符号表。然而,当每次进入一个PHP函数时(此处指的是用户利用PHP代码创立的函数),Zend城市创立函数部分的变量符号表,并将active_symbol_table指向部分符号表。Zend老是利用active_symbol_table来会见变量,如许就完成下场部变量的感化域掌握。
  但假如在函数部分会见标志为global的变量,Zend会停止特别处置――在active_symbol_table中创立symbol_table中同名变量的援用,假如symbol_table中没有同名变量则会先创立。
  1.3 内存和文件
  法式具有的资本普通包含内存和文件,关于凡是的法式,这些资本是面向历程的,当历程停止后,操作体系或C库会主动收受接管那些咱们没有显式释放的资本。
  然而,PHP法式有其特别性,它是基于页面的,一个页面运转时一样也会请求内存或文件如许的资本,但是当页面运转停止后,操作体系或C库或许不会晓得需求停止资本收受接管。好比,咱们将php作为模块编译到apache里,而且以prefork或worker形式运转apache。这类情形下apache历程或线程是复用的,php页面分派的内存将永驻内存直到出core。
  为懂得决这类成绩,Zend供应了一套内存分派API,它们的感化和C中响应函数一样,分歧的是这些函数从Zend本人的内存池平分配内存,而且它们可以完成基于页面的主动收受接管。在咱们的模块中,为页面分派的内存应当利用这些API,而不是C例程,不然Zend会在页面停止时测验考试efree失落咱们的内存,其了局凡是就是crush。
  emalloc()
  efree()
  estrdup()
  estrndup()
  ecalloc()
  erealloc()
  别的,Zend还供应了一组形如VCWD_xxx的宏用于替换C库和操作体系响应的文件API,这些宏可以撑持PHP的虚拟任务目次,在模块代码中应当老是利用它们。宏的详细界说拜见PHP源代码”TSRM/tsrm_virtual_cwd.h”。能够你会注重到,一切那些宏中并没有供应close操作,这是由于close的对象是已翻开的资本,不触及到文件途径,因而可以直接利用C或操作体系例程;同理,read/write之类的操作也是直接利用C或操作体系的例程。
<P style="TEXT-INDENT: 2em">
理解网站这一概念之后不难看出,任何网站都是由网页组成的,也就是说想完成网站,必须先学会做网页,因此必须要掌握了HTML,才能为今后制作网站打下基础。
谁可相欹 该用户已被删除
沙发
发表于 2015-2-16 00:36:39 | 只看该作者
学好程序语言,多些才是王道,写两个小时代码的作用绝对超过看一天书,这个我是深有体会(顺便还能练打字速度)。
深爱那片海 该用户已被删除
板凳
发表于 2015-3-4 19:24:11 | 只看该作者
说点我烦的低级错误吧,曾经有次插入mysql的时间 弄了300年结果老报错,其实mysql的时间是有限制的,大概是到203X年  具体的记不清啦,囧。
小魔女 该用户已被删除
地板
发表于 2015-3-11 20:48:51 | 只看该作者
要进行开发,搭建环境是首先需要做的事,windows下面我习惯把环境那个安装在C盘下面,因为我配的环境经常出现诡异事件,什么事都没做环境有的时候就不能用啦。
不帅 该用户已被删除
5#
发表于 2015-3-19 12:28:07 | 只看该作者
最后介绍一个代码出错,但是老找不到错误方法,就是 go to wc (囧),出去换换气没准回来就找到错误啦。
乐观 该用户已被删除
6#
 楼主| 发表于 2015-3-27 20:18:52 | 只看该作者
因为blog这样的可以让你接触更多要学的知识,可以接触用到类,模板,js ,ajax
第二个灵魂 该用户已被删除
7#
发表于 2015-4-3 14:17:42 | 只看该作者
曾经犯过一个很低级的错误,我在文件命名的时候用了一个横线\\\\\\\'-\\\\\\\' 号,结果找了好几个小时的错误,事实是命名的时候 是不能用横线 \\\\\\\'-\\\\\\\' 的,应该用的是下划线  \\\\\\\'_\\\\\\\' ;
莫相离 该用户已被删除
8#
发表于 2015-4-7 16:50:32 | 只看该作者
我学习了一段时间后,我发现效果并不好(估计是我自身的问题)。因为一个人的精力总是有限的,同时学习这么多,会导致每个的学习时间都得不到保证。
冷月葬花魂 该用户已被删除
9#
发表于 2015-4-10 19:51:35 | 只看该作者
建议加几个专业的phper的群,当然啦需要说话的人多,一处一点问题能有人回答你的,当然啦要让人回答你的问题,平时就得躲在里面聊天,大家混熟啦,愿意回答你问题的人自然就多啦。
金色的骷髅 该用户已被删除
10#
发表于 2015-4-12 23:01:42 | 只看该作者
我学习了一段时间后,我发现效果并不好(估计是我自身的问题)。因为一个人的精力总是有限的,同时学习这么多,会导致每个的学习时间都得不到保证。
变相怪杰 该用户已被删除
11#
发表于 2015-5-1 05:12:13 | 只看该作者
其实没啥难的,多练习,练习写程序,真正的实践比看100遍都有用。不过要熟悉引擎
柔情似水 该用户已被删除
12#
发表于 2015-5-9 12:09:19 | 只看该作者
在学习的过程中不能怕麻烦,不能有懒惰的思想。学习php首先应该搭建一个lamp环境或者是wamp环境。这是学习php开发的根本。虽然网络上有很多集成的环境,安装很方便,使用起来也很稳定、
因胸联盟 该用户已被删除
13#
发表于 2015-5-9 18:39:24 | 只看该作者
其实没啥难的,多练习,练习写程序,真正的实践比看100遍都有用。不过要熟悉引擎
老尸 该用户已被删除
14#
发表于 2015-5-11 06:30:11 | 只看该作者
,熟悉html,能用div+css,还有javascript,优先考虑linux。我在开始学习的时候,就想把这些知识一起学习,我天真的认为同时学习能够互相呼应,因为知识是相通的。
简单生活 该用户已被删除
15#
发表于 2015-6-4 04:41:10 | 只看该作者
如果你可以写完像留言板这样的程序,那么你可以去一些别人的代码了,
若天明 该用户已被删除
16#
发表于 2015-6-13 20:04:56 | 只看该作者
本文当是我的笔记啦,遇到的问题随时填充
愤怒的大鸟 该用户已被删除
17#
发表于 2015-6-18 10:49:16 | 只看该作者
曾经犯过一个很低级的错误,我在文件命名的时候用了一个横线\\\\\\\'-\\\\\\\' 号,结果找了好几个小时的错误,事实是命名的时候 是不能用横线 \\\\\\\'-\\\\\\\' 的,应该用的是下划线  \\\\\\\'_\\\\\\\' ;
飘灵儿 该用户已被删除
18#
发表于 2015-6-20 14:28:16 | 只看该作者
学好程序语言,多些才是王道,写两个小时代码的作用绝对超过看一天书,这个我是深有体会(顺便还能练打字速度)。
灵魂腐蚀 该用户已被删除
19#
发表于 2015-6-27 00:21:14 | 只看该作者
Ps:以上纯属原创,如有雷同,纯属巧合
活着的死人 该用户已被删除
20#
发表于 2015-7-7 10:17:11 | 只看该作者
爱上php,他也会爱上你。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|仓酷云 鄂ICP备14007578号-2

GMT+8, 2024-12-22 23:44

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表