#一、php的变量定义:变量用于存储值,比如数字、文本字符串或数组、五中:string /integer /double /array /object
命名规则:
1、php的变量名是区分大小写的。2、变量名必须以$开头3、变量名开头可以是下划线4、变量名不能以数字字符开头
5.$this 是一个特殊的变量,它不能被赋值。
#二、php变量的赋值
*只有有名字的变量才可以引用赋值:
#变量默认值
虽然在 php 中并不需要初始化变量,但对变量进行初始化是个好习惯。未初始化的变量具有其类型的默认值
- 布尔类型的变量默认值是 false,
- 整形和浮点型变量默认值是零,
- 字符串型变量默认值是空字符串null或者数组变量的默认值是空数组。
*依赖未初始化变量的默认值在某些情况下会有问题,例如把一个文件包含到另一个之中时碰上相同的变量名。
另外把php.in register_globals 打开是一个主要的安全隐患。使用未初始化的变量会发出e_notice错误,
但是在向一个未初始化的数组附加单元时不会。
isset() 语言结构可以用来检测一个变量是否已被初始化。
25var_dump($unset_int);// float/double usage; outputs 'float(1.25)'$unset_float += 1.25;var_dump($unset_float);// array usage; outputs array(1) { [3]=> string(3) def }$unset_arr[3] = def; // array() + array(3 => def) => array(3 => def)var_dump($unset_arr);// object usage; creates new stdclass object // outputs: object(stdclass)#1 (1) { [foo]=> string(3) bar }$unset_obj->foo = 'bar';$unset_obj->shit = '234';var_dump($unset_obj);var_export($unset_obj);?>
#预定义变量
warning php 4.2.0 以及后续版本中,php 指令 register_globals 的默认值为 off。这是 php 的一个主要变化。让 register_globals 的值为 off 将影响到预定义变量集在全局范围内的有效性。例如,为了得到 document_root 的值,将必须使用 $_server['document_root'] 代替$document_root,又如,使用 $_get['id'] 来代替 $id 从 url http://www.example.com/test.php?id=3 中获取 id 值,亦或使用$_env['home'] 来代替 $home 获取环境变量 home 的值。
更多相关信息,请阅读 register_globals 的配置项条目,安全一章中的使用 register globals,以及 php » 4.1.0 和 » 4.2.0 的发布公告。
如果有可用的 php 预定义变量那最好用,如超全局数组。
从 php 4.1.0 开始,php 提供了一套附加的预定数组,这些数组变量包含了来自 web 服务器(如果可用),运行环境,和用户输入的数据。这些数组非常特别,它们在全局范围内自动生效,例如,在任何范围内自动生效。因此通常被称为自动全局变量(autoglobals)或者超全局变量(superglobals)。(php 中没有用户自定义超全局变量的机制。)超全局变量罗列于下文中;但是为了得到它们的内容和关于 php 预定义变量的进一步的讨论以及它们的本质,请参阅预定义变量。而且,你也将注意到旧的预定义数组($http_*_vars)仍旧存在。自 php 5.0.0 起, 用 register_long_arrays 设置选项可禁用 长类型的 php 预定义变量数组。
note: 可变变量
超级全局变量不能被用作可变变量。
note:
尽管超全局变量和 http_*_vars 同时存在。但是他们并不是同一个变量,所以改变一个的值并不会对另一个产生影响。
如果某些 variables_order 中的变量没有设定,它们的对应的 php 预定义数组也是空的。
预定义变量对于全部脚本而言,php 提供了大量的预定义变量。这些变量将所有的外部变量表示成内建环境变量,并且将错误信息表示成返回头。参见 faq “register_globals 对我有什么影响?”table of contents超全局变量 ? 超全局变量是在全部作用域中始终可用的内置变量$globals ? 引用全局作用域中可用的全部变量$_server ? 服务器和执行环境信息$_get ? http get 变量$_post ? http post 变量$_files ? http 文件上传变量$_request ? http request 变量$_session ? session 变量$_env ? 环境变量
$_cookie ? http cookies$php_errormsg ? 前一个错误信息$http_raw_post_data ? 原生post数据$http_response_header ? http 响应头$argc ? 传递给脚本的参数数目$argv ? 传递给脚本的参数数组
#可变变量
有时候使用可变变量名是很方便的。就是说,一个变量的变量名可以动态的设置和使用。
要将可变变量用于数组,必须解决一个模棱两可的问题。这就是当写下 $$a[1] 时,解析器需要知道是想要 $a[1] 作为一个变量呢,
还是想要 $$a 作为一个变量并取出该变量中索引为 [1] 的值。解决此问题的语法是,对第一种情况用 ${$a[1]},对第二种情况用 ${$a}[1]。
#变量函数
variable handling 函数array_key_exists
table of contents isset ? 检测变量是否设置 unset ? 释放给定的变量 empty ? 检查一个变量是否为空 var_dump ? 打印变量的相关信息 var_export ? 输出或返回一个变量的字符串表示 print_r ? 打印关于变量的易于理解的信息。 serialize ? 产生一个可存储的值的表示 settype ? 设置变量的类型 strval ? 获取变量的字符串值 unserialize ? 从已存储的表示中创建 php 的值 is_null ? 检测变量是否为 null is_array ? 检测变量是否是数组 is_bool ? 检测变量是否是布尔型 is_callable ? 检测参数是否为合法的可调用结构 is_double ? is_float 的别名 is_float ? 检测变量是否是浮点型 is_int ? 检测变量是否是整数 is_integer ? is_int 的别名 is_long ? is_int 的别名 is_numeric ? 检测变量是否为数字或数字字符串 is_object ? 检测变量是否是一个对象 is_real ? is_float 的别名 is_resource ? 检测变量是否为资源类型 is_scalar ? 检测变量是否是一个标量 is_string ? 检测变量是否是字符串 array_key_exists(mixed key, array search) 检查给定的键名或索引是否存在于数组中 debug_zval_dump ? dumps a string representation of an internal zend value to output doubleval ? floatval 的别名 floatval ? 获取变量的浮点值 get_defined_vars ? 返回由所有已定义变量所组成的数组 get_resource_type ? 返回资源(resource)类型 gettype ? 获取变量的类型 import_request_variables ? 将 get/post/cookie 变量导入到全局作用域中 intval ? 获取变量的整数值 *各种数据类型 函数输出比较
表p.1.用 php 函数对 $x 的比较表达式 gettype() empty() is_null() isset() boolean : if($x)$x = ; string true false true false$x = null null true true false falsevar $x; null true true false false$x 尚未定义 null true true false false$x = array(); array true false true false$x = false; boolean true false true false$x = true; boolean false false true true$x = 1; integer false false true true$x = 42; integer false false true true$x = 0; integer true false true false$x = -1; integer false false true true$x = 1; string false false true true$x = 0; string true false true false$x = -1; string false false true true$x = php; string false false true true$x = true; string false false true true$x = false; string false false true true
#变量范围
变量范围
变量的范围即它定义的上下文背景(也就是它的生效范围)。大部分的 php 变量只有一个单独的范围。
这个单独的范围跨度同样包含了 include 和 require 引入的文件。例如:这里变量 $a 将会在包含文件 b.inc 中生效:
这个脚本不会有任何输出,因为 echo 语句引用了一个局部版本的变量 $a,而且在这个范围内,它并没有被赋值。
php 中全局变量在函数中使用时必须申明为global。以上脚本的输出将是“3”。在函数中申明了全局变量 $a 和 $b,任何变量的所有引用变量都会指向到全局变量。
在全局范围内访问变量的第二个办法,是用特殊的 php 自定义 $globals 数组。前面的例子可以写成:
$globals 是一个关联数组,每一个变量为一个元素,键名对应变量名,值对应变量的内容。 $globals 之所以在全局范围内存在,是因为 $globals 是一个超全局变量。以下范例显示了超全局变量的用处: example #3 演示超全局变量和作用域的例子
使用静态变量static variable 静态变量仅在局部函数域中存在,但当程序执行离开此作用域时,其值并不丢失。看看下面的例子: example #4 演示需要静态变量的例子
$a 的值设为 0 并输出 0。
将变量加一的 $a++ 没有作用,因为一旦退出本函数则变量 $a 就不存在了。
要写一个不会丢失本次计数值的计数函数,要将变量 $a 定义为静态的:
example #5 使用静态变量的例子
现在,变量$a在第一调用test()时被初始化,每次调用 test() 函数都会输出 $a 的值并加一。
静态变量也提供了一种处理递归函数的方法。递归函数是一种调用自己的函数。写递归函数时要小心,因为可能会无穷递归下去。必须确保有充分的方法来中止递归。一下这个简单的函数递归计数到 10,使用静态变量 $count 来判断何时停止:
example #6 静态变量与递归函数
property++;
return $obj;
}
$obj1 = get_instance_ref();
$still_obj1 = get_instance_ref();
echo \n;
$obj2 = get_instance_noref();
$still_obj2 = get_instance_noref();
?>
执行以上例子会导致如下输出:
static object: null
static object: null
static object: null
static object: object(stdclass)(1) {
[property]=>
int(1)
}
上例演示了当把一个引用赋值给一个静态变量时,第二次调用 &get_instance_ref() 函数时其值并没有被记住。
#扩展:[部分摘自网络]
一、定义(c描述): //----------------------------------------------- typedef struct _zval_struct zval; typedef union _zvalue_value { long lval; double dval; struct { char *val; int len; } str; hashtable *ht; zend_object_value obj; } zvalue_value; struct _zval_struct { zvalue_value value; //php变量值,联合类型。可接受各种数据类型的值。 zend_uchar type; //php变量类型 zend_uchar is_ref; //是否为引用 zend_uint refcount; //引用个数 }; //-----------------------------------------------(zend.h) 结构体zval即为所描述的php变量。 二、操作 1。定义一个变量,并赋值。如$a=1; 内部所执行的操作大概为: ①定义一个zval变量a。②为变量a分配内存,并初始化。③为变量a赋值。④将变量a添加到符号表中 //----------------------------------------------- zval *a; //① make_std_zval(a); //② zval_long(a, 1); //③ zend_set_symbol(eg(active_symbol_table), “local_variable”, a); //④ //----------------------------------------------- 注: 其中②的具体操作为: #define make_std_zval(zv) \ alloc_zval(zv); \ //分配内存 init_pzval(zv); //初始化 #define alloc_zval(z) \ //分配内存 zend_fast_alloc(z, zval, zval_cache_list) #define zend_fast_alloc(p, type, fc_type) \ (p) = (type *) emalloc(sizeof(type)) #define emalloc(size) _emalloc((size) zend_file_line_cc zend_file_line_empty_cc) zend_api void *_emalloc(size_t size zend_file_line_dc zend_file_line_orig_dc) { tsrmls_fetch(); if (unexpected(!ag(mm_heap)->use_zend_alloc)) { return malloc(size); //通过c函数操作内存 } return _zend_mm_alloc_int(ag(mm_heap), size zend_file_line_relay_cc zend_file_line_orig_relay_cc); } #define init_pzval(z) \ //初始化 (z)->refcount = 1; \ //引用个数为1 (z)->is_ref = 0; //变量没有被引用 其中④的具体操作为: 先会检查一下要添加的变量是否已经存在在符号表中, 若存在,则不存储,把对应的refcount加一。 若不存在,则添加在符号表后面。 可查看zend_api.h文件中zend_set_symbol_with_length的宏定义。 2。把一个变量的值赋给另一个变量。如:$a=1;$b=$a; 内部所执行的操作大概为: 不申请新的内存空间,直接把变量b添加进符号表,然后指向变量a所指的内存空间。 即把变量的refcount加一。#define zval_addref(pz) (++(pz)->refcount)。但各自的is_ref都为0。 3。unset一个变量。如$a=1;$b=$a;unset($b); 内部所执行的操作大概为: 检查变量的refcount是否大于1,若大于1,说明还有别的变量也在关注此内存空间,则把refcount减一,即#define zval_delref(pz) (--(pz)->refcount)。若等于1,则直接释放变量空间,即free_zval(var)。 4。非引用的两个变量共享同一内存空间,当其中一个被赋于新值时。如:$a=1;$b=$a;$b=2; 内部所执行的操作大概为: ①执行$a=1;后,变量a的is_ref为0,refcount为1。②执行$b=$a;后,is_ref变为0,refcount变为2。变量a、b指向了同一内存空间③执行$b=2;时,先判断is_ref,若为0,说明没有被引用,则调用分离变量宏,把refcount减一,为变量划分新的内存空间、初始化,并赋新值。若为1,说明有被引用,可直接赋值。 #define separate_zval_if_not_ref(ppzv) \ if (!pzval_is_ref(*ppzv)) { \ separate_zval(ppzv); \ } #define separate_zval(ppzv) \ { \ zval *orig_ptr = *(ppzv); \ \ if (orig_ptr->refcount>1) { \ orig_ptr->refcount--; \ alloc_zval(*(ppzv)); \ **(ppzv) = *orig_ptr; \ zval_copy_ctor(*(ppzv));\ (*(ppzv))->refcount=1; \ (*(ppzv))->is_ref = 0; \ } \ } 5。被引用的两个变量,其中一个被赋新值。如:$a=1;$b=&$a;$b=2; 内部所执行的操作大概为: ①执行$a=1;后,变量a的is_ref为0,refcount为1。②执行$b=&$a;后,is_ref变为1,refcount变为2。③执行$b=2;时,先判断is_ref,若为0,则调用分离变量宏。若为1,则直接赋值。 #define replace_zval_value(ppzv_dest, pzv_src, copy) { \ int is_ref, refcount; \ \ separate_zval_if_not_ref(ppzv_dest); \ //判断是否被引用,并执行相应操作。 is_ref = (*ppzv_dest)->is_ref; \ refcount = (*ppzv_dest)->refcount; \ zval_dtor(*ppzv_dest); \ **ppzv_dest = *pzv_src; \ if (copy) { \ zval_copy_ctor(*ppzv_dest); \ } \ (*ppzv_dest)->is_ref = is_ref; \ (*ppzv_dest)->refcount = refcount; \ } 6。分离①:如$a=1;$b=$a;$c=&$a; 内部所执行的操作大概为: ①执行$a=1;后,is_ref为0,refcount为1。②执行$b=$a;后,is_ref为0,refcount变为2。③执行$c=&$a;时,变量b被分离出来,重新划分内存空间。变量a、c指向原本变量a的空间。变量b的is_ref为0,refcount为1。变量a、c的is_ref为1,refcount为2。 7。分离②:如$a=1;$b=&$a;$c=$a; 内部所执行的操作大概为: ①执行$a=1;后,is_ref为0,refcount为1。②执行$b=&$a;后,is_ref为1,refcount变为2。③执行$c=$a;时,变量c被分离出来,划分新空间,is_ref为0,refcount为1。变量a、b保持原来的引用不变,is_ref为1,refcount为2。 8。对全局变量和局部变量的存储。在内部,有很多个哈希表,有些是用来管理数组用的,有些管理对象用的,还有两个是用来管理php变量的,一个是全局变量哈希表,一个是局部变量哈希表。 需要向系统登记的变量,只要调用zend_set_symbol(eg(active_symbol_table), local_variable, new_var1);(登记为局部变量)或zend_set_symbol(&eg(symbol_table), global_variable, new_var2);(登记为全局变量)。哈希表结构可查看zend_hash.h文件。 附: 1。对系统核心的操作,可尽量考虑提高其操作的执行效率。 如可用“多行宏定义”替代“无返回值小函数”来提高执行速度。因为宏定义,是在程序编译时,把宏体直接替换到调用其对应宏名的地方,省去了c语言中对函数调用的一系列操作(如:保存当前变量状态,函数相关信息进栈、出栈等操作)。 2。编译型语言中,变量须先定义,后使用。在编译时就为全部变量划分好了内存空间。 而解释型语言中,运行时要用到变量的时候,才去申请内存空间。这样可省去定义变量的麻烦,不过有些隐藏的语法错误要在运行时才可被发现。 3。操作内存时,可尽量考虑减少内存的使用。如$a=1;$b=$a;。内部操作其实只是将变量a、b指向同一内存区域。这样做的好处,一方面可节约内存,另一方面,减少操作步骤,提高系统的执行速度。因为省去了申请内存空间,初始化,赋值的一些操作,而只是简单得把变量b添加到符号表,并指向a所指的内存区域。等到必要的,才对变量a、b的内存区域进行分离。如遇到$b=2;。 4。有些疑惑的地方。 ①按照以上定义的php变量结构体zval,当我们定义一个long型变量,按理,该变量内部的“type”成员的值应该为long,而且可以储存的数的范围为:(4个字节)-2^31+1~2^31。当实际定义一个php变量并赋值时,发现,当超过long能表示的范围时,会自动向double转化。 ②double类型为8个字节,能存储的范围为:-2^63+1~2^63。当实际定义一个php变量并赋值时,发现,其可表示的数超过1.0e+260。这已经超过double能表示的范围。 我猜想,内部应该有一个专门用来处理变量类型转化,扩大变量的数据存储能力的程序段。这好象就是泛类型,不太懂。不过我没有找到相关的程序段。 结论:使用php变量,可不用太担心变量的数据溢出问题。
#
