仓酷云
标题:
PHP编程:深切PHP利用技能之变量
[打印本页]
作者:
再见西城
时间:
2015-2-3 23:34
标题:
PHP编程:深切PHP利用技能之变量
学习数据库了,MYSQL可算是PHP的黄金搭档了,不过,虽然话是这么说,你也可能恨不得把MYSQL给生吞活剥了,因为这一行一列的东东简直让自己头晕目眩。 尽人皆知,PHP与其他剧本言语一样,属于弱变量类型的言语。同时PHP自己也是经由过程C言语来完成。本文次要引见PHP外部是若何完成弱变量类型的,而且据此剖析在PHP开辟中需求注重的一些利用手艺。个中会重点剖析PHP中的copy on write机制和援用相干方面的话题。 本章节属于《深切PHP利用技能》的第一局部。
若何完成弱变量
在懂得PHP完成弱变量类型之前,可以先思虑下:若何经由过程C/C++来完成弱变量类型的后果呢?
这个成绩我在BIT培训课上根基上有两种谜底:
办法1:采取C++的承继机制。起首界说一个基本类型
Class Var
{
}
然后基于Var,派生出分歧的子类型IntVar/FloatVar/StringVar等等。
办法2:基于C言语的 Struct。个中一个字段用于标识类型,别的一个字段用于存储数据,因为数据如果各类类型,所以凡是需求采取指针
好比:
struct var {
Int type;
Void *data;
};
两种思绪自己并没有太大区分,也都根基上可以知足需求。在PHP中采取了第二种思绪,而且做了对照多的优化。在PHP中,一切的变量城市对应统一品种型zval,个中zval也就是struct _zval_struct,详细界说以下:
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;
};
从zval可以看出,PHP在细节方面切实其实做了很多优化的工夫。
1.zend_uchar type。采取uchar节俭内存。
2.zvalue_value value; 采取union来交换void *,如许一样能节俭空间,而且比void *更能表义明晰。
3.在字符串类型中,默许保存了字符串的长度。如许很轻易做到字符串的二进制平安,而且在盘算字符串长度的时分不需求停止扫描。
察看PHP弱变量的完成,也会有以下困惑:
1.为何会没有int类型呢?其其实PHP中是有的,只是说默许int数据就保留在long中。
2.资本类型咋体现的呢?资本在PHP外部其实就是一数字。具体后续会引见。
3.refcount和is_ref是干吗的呢?呵呵,这就是第二局部要引见的了。
Reference counting & Copy-on-Write
PHP和其他言语相似,在其语法中有两种赋值体例:援用赋值和非援用赋值(通俗的==赋值)。
<?php
$a = 1;
$b = $a;//非援用赋值
$c = &$a;//援用赋值
?>
援用赋值和非援用赋值在PHP外部是若何完成的呢?一种凡是的熟悉是:“援用赋值就是两个变量对应统一个Zval,非援用赋值则是直接发生一个新的zval,同时把对应的值直接copy过去。”也就是该代码的内存布局以下:
登录/注册后可看大图
(该图是大多半人以为的PHP内存布局,是毛病的)
如许切实其实可以知足大局部情形下的需求,但明显不是最好的处理计划,特别是在内存办理上,好比说以下代码就会显得十分的低效。
<?php
$arr = array(...);//界说一个十分大的PHP数组
myfunc($arr);//每个函数挪用都是一次隐性的非援用赋值
myfunc($arr);
?>
由于每次函数挪用会停止一次内存dump,而大内存的内存dump长短常耗CPU的。在C言语中,一种处理计划是采取指针,一切函数挪用尽可能传递指针。切实其实很天真高效,但也很难保护~指针可以说是C言语法式员心头的痛(固然也是福~^_^)。还有一种更初级更无效的办法是采取援用计数(Reference counting)。
在PHP中,也能够采取援用来处理如许的成绩,但你见过采取在PHP中大批利用援用的吗?明显很少。
在PHP内核中,Zval的完成恰是采取了援用计数的概念,说起援用计数就不能不谈到copy-on-write 机制。如许后面谈到的refcount和is_ref就有感化了。
refcount:援用次数。在zval初始创立的时分就为1。每增添一个援用,则refcount ++。
is_ref:用于暗示一个zval是不是是援用形态。zval初始化的情形下会是0,暗示不是援用。
在Zend/Zend.h外部有一些关于ZVAL的宏界说,外面对照明晰的解析了援用计数的一些划定规矩,个中重点存眷以下几个宏界说
#define INIT_PZVAL(z) \
(z)->refcount = 1; \
(z)->is_ref = 0;
#define SEPARATE_ZVAL_IF_NOT_REF(ppzv) \//非援用下的变量分别
if (!PZVAL_IS_REF(*ppzv)) { \
SEPARATE_ZVAL(ppzv); \
}
#define SEPARATE_ZVAL_TO_MAKE_IS_REF(ppzv) \//非援用下的变量分别,而且设置援用
if (!PZVAL_IS_REF(*ppzv)) { \
SEPARATE_ZVAL(ppzv); \
(*(ppzv))->is_ref = 1; \
}
#define SEPARATE_ARG_IF_REF(varptr) \ //援用下的变量分别
if (PZVAL_IS_REF(varptr)) { \
zval *original_var = varptr; \
ALLOC_ZVAL(varptr); \
varptr->value = original_var->value; \
varptr->type = original_var->type; \
varptr->is_ref = 0; \
varptr->refcount = 1; \
zval_copy_ctor(varptr); \
} else { \
varptr->refcount++; \
}
这外面谈到两个主要的概念:
1、非援用下的变量分别。
非援用下的变量分别,是指在一堆非援用变量中拔出援用的情形下,在PHP外部停止的一种内存操作。以上面的列子来看:
$a = 1;
$b = $a;
$c = &$b;
在前两句履行以后,内存布局以下图
登录/注册后可看大图
在第三句 $c = &$b;语句中则会履行“非援用下的变量分别。”,详细步调是:
将b分别出来,同时把a对应的zval的refcount-1。
copy 出一个新的zval,并把zval的is_ref设置成1.
把C指向这个新的zval,同时refcount ++
终究后果以下图:
登录/注册后可看大图
2、援用下的变量分别。
援用下的变量分别,是指在一堆援用变量中停止一个非援用赋值操作,这个时分会直接履行copy内存的操作。
以上面的例子来讲
$a = 1;
$b = &$a;
$c = $b;
在履行完前两行后,PHP中内存布局以下:
登录/注册后可看大图
在第三句,则会履行“援用下的变量分别”也就是真实的copy,终究内存布局以下图
登录/注册后可看大图
据此,根基上对PHP变量外部的一些道理对照清晰了,但还有一些需求注重点的:
1、PHP变量的援用计数特征,关于数组一样也存在。但注重,关于key则不失效。(详细在前面章节会剖析到。)
2、PHP变量中的对象对照特别,在PHP5以后,默许都是采取援用赋值的体例。详细完成可以参考Zend_objects.*系列代码。
3、关于剖析PHP外部变量,保举采取xdebug_debug_zval,而不要采取内置的debug_zval_dump。由于PHP内置的debug_zval_dump函数一方面没法处置is_ref,并且采取了援用的体例来处置,从而招致看到了局会有曲解。
利用技能结论
据此可以得出剖析出很多结论:
1、在PHP开辟中不保举采取援用。由于PHP外部对内存优化自己做了很多任务,援用不会带来太多优化。(但注重保举非强迫)
2、在PHP中strlen是o(1)的。
说说这一个月左右的学习情况和心得吧!我个人认为,既然决定了去做一件事,那就要以认真的态度去对待!既然决定来学习了,那不管当初是抱着怎样的心态来到这个培训班的,都要让自己认真的投入到学习中。
作者:
飘灵儿
时间:
2015-2-4 02:22
刚开始安装php的时候,我图了个省事,把php的扩展全都打开啦(就是把php.ini 那一片 extension 前面的冒号全去掉啦),这样自然有好处,以后不用再需要什么功能再来打开。
作者:
老尸
时间:
2015-2-4 13:15
php是动态网站开发的优秀语言,在学习的时候万万不能冒进。在系统的学习前,我认为不应该只是追求实现某种效果,因为即使你复制他人的代码调试成功,实现了你所期望的效果,你也不了解其中的原理。
作者:
第二个灵魂
时间:
2015-2-9 23:21
Apache不是非得用80或者8080端口的,我刚开始安得时候就是80端口老占用,就用了个 81端口,结果照常,就是输localhost的时候,应该输入为 localhost:81
作者:
admin
时间:
2015-2-26 05:57
作为一个合格的coder 编码的规范是必须,命名方面我推崇“驼峰法”,另外就是自己写的代码最好要带注释,不然时间长了,就算是自己的代码估计看起来都费事,更不用说别人拉。
作者:
若天明
时间:
2015-3-8 12:14
其实没啥难的,多练习,练习写程序,真正的实践比看100遍都有用。不过要熟悉引擎
作者:
蒙在股里
时间:
2015-3-9 20:58
如果你可以写完像留言板这样的程序,那么你可以去一些别人的代码了,
作者:
乐观
时间:
2015-3-10 23:01
先学习php和mysql,还有css(html语言很简单)我认为现在的效果比以前的方法好。
作者:
深爱那片海
时间:
2015-3-11 21:48
爱上php,他也会爱上你。
作者:
冷月葬花魂
时间:
2015-3-15 16:58
建数据库表的时候,int型要输入长度的,其实是个摆设的输入几位都没影响的,只要大于4就行,囧。
作者:
变相怪杰
时间:
2015-3-19 05:41
使用 jquery 等js框架的时候,要随时注意浏览器的更新情况,不然很容易发生框架不能使用。
作者:
因胸联盟
时间:
2015-3-27 08:08
环境搭建好,当你看见你的浏览器输出“it works\\\\\\\"时你一定是喜悦的。在你解决问题的时候,我强烈建议多读php手册。
作者:
再现理想
时间:
2015-3-27 15:08
真正的方向了,如果将来要去开发团队,你一定要学好smarty ,phplib这样的模板引擎,
作者:
山那边是海
时间:
2015-4-4 09:55
学习php的目的往往是为了开发动态网站,phper就业的要求也涵盖了很多。我大致总结为:精通php和mysql
作者:
若相依
时间:
2015-4-6 23:11
不禁又想起那些说php是草根语言的人,为什么认得差距这么大呢。
作者:
小魔女
时间:
2015-4-13 15:03
使用 jquery 等js框架的时候,要随时注意浏览器的更新情况,不然很容易发生框架不能使用。
作者:
爱飞
时间:
2015-4-21 16:07
,熟悉html,能用div+css,还有javascript,优先考虑linux。我在开始学习的时候,就想把这些知识一起学习,我天真的认为同时学习能够互相呼应,因为知识是相通的。
作者:
愤怒的大鸟
时间:
2015-4-25 02:45
我学习了一段时间后,我发现效果并不好(估计是我自身的问题)。因为一个人的精力总是有限的,同时学习这么多,会导致每个的学习时间都得不到保证。
作者:
透明
时间:
2015-6-14 02:02
有时候汉字的空格也能导致页面出错,所以在写代码的时候,要输入空格最好用引文模式。
作者:
不帅
时间:
2015-6-17 19:54
本人接触php时间不长,算是phper中的小菜鸟一只吧。由于刚开始学的时候没有名师指,碰过不少疙瘩,呗很多小问题卡过很久,白白浪费不少宝贵的时间,在次分享一些子的学习的心得。
欢迎光临 仓酷云 (http://ckuyun.com/)
Powered by Discuz! X3.2