文章标题:21天学会PHP
发布时间:2015.12.17
第2天:标记,类型,变量
2.1 PHP标记
当解析一个文件时,PHP 会寻找起始和结束标记,也就是 <?php 和 ?>,这告诉 PHP 开始和停止解析二者之间的代码。此种解析方式使得 PHP 可以被嵌入到各种不同的文档中去,而任何起始和结束标记之外的部分都会被 PHP 解析器忽略。
PHP 也允许使用短标记 <? 和 ?> ,但是官方不鼓励这种方式,这里也不做详细说明。
如果文件内容是纯 PHP 代码,最好在文件末尾删除 PHP 结束标记
?>
。这可以避免在 PHP 结束标记之后万一意外加入了空格或者换行符,会导致PHP开始输出这些空白,使程序难以调试。
2.1.1 代码分隔符
同C语言一样,PHP需要在每个语句后用分号结束。一段PHP代码中的结束标记隐含表示了一个分号 ;
。
2.1.2 PHP注释
PHP支持C/C++语言风格注释,并且确保不要对多行注释进行嵌套
<?php
//这是一个PHP支持的单行注释
/*
这是一个PHP支持的多行注释
*/
/*
/* 这种嵌套的写法是错误的 */
*/
?>
2.2 数据类型
PHP 支持 8 种原始数据类型
四种标量类型:
boolean(布尔型)
integer(整型)
float(浮点型,也称作 double)
string(字符串)
两种复合类型:
array(数组)
object(对象)
两种特殊类型:
resource(资源)
NULL(无类型)
2.2.1 Boolean 布尔类型
这是最简单的类型。boolean 表达了真值,可以为 TRUE 或 FALSE,要指定一个布尔值,使用关键字 TRUE 或 FALSE。两个都不区分大小写,如下:
$var = True; // 将 True 值赋值给了$var变量
$var = False; // 将 False 值赋值给了$var变量
2.2.2 Integer 整型
整型值可以使用十进制,十六进制,八进制或二进制表示,前面可以加上可选的符号(- 或者 +)。
要使用八进制表达,数字前必须加上 0(零)。要使用十六进制表达,数字前必须加上 0x。要使用二进制表达,数字前必须加上 0b(PHP5.4起可用)。
示例如下:
$a = 1234; // 十进制数
$a = -123; // 负数
$a = 0123; // 八进制数 (等于十进制 83)
$a = 0x1A; // 十六进制数 (等于十进制 26)
有以下几点需要注意:
整型数的字长和平台有关,尽管通常最大值是大约二十亿(32 位有符号),64 位平台下的最大值通常是大约 9E18
Integer 值的字长可以用常量 PHP_INT_SIZE来表示,自 PHP 4.4.0 和 PHP 5.0.5后,最大值可以用常量 PHP_INT_MAX 来表示
如果向八进制数传递了一个非法数字(即 8 或 9),则后面其余数字会被忽略
如果给定的一个数超出了 integer 的范围,将会被解释为 float,同样如果执行的运算结果超出了 integer 范围,也会返回 float
PHP 中没有整除的运算符。1/2 产生出 float 0.5,值可以舍弃小数部分强制转换为 integer,或者使用 round() 函数可以更好地进行四舍五入
要明确地将一个值转换为 integer,用 (int) 或 (integer) 强制转换,不过大多数情况下都不需要强制转换,因为当运算符,函数或流程控制需要一个 integer 参数时,值会自动转换,还可以通过函数 intval() 来将一个值转换成整型
千万不要将未知的分数强制转换为 integer,这样有时会导致不可预料的结果
2.2.3 Float 浮点型
浮点型(也叫浮点数 float,双精度数 double 或实数 real)可以用以下任一语法定义:
$a = 1.234;
$b = 1.2e3;
$c = 7E-10;
对于浮点数的一些特别需要关注的地方:
浮点数的精度有限,尽管取决于系统,PHP 通常使用 IEEE 754 双精度格式,则由于取整而导致的最大相对误差为 1.11e-16。非基本数学运算可能会给出更大误差,并且要考虑到进行复合运算时的误差传递。
永远不要相信浮点数结果精确到了最后一位,也永远不要比较两个浮点数是否相等。
判断浮点数是否相等可以使用一个仅比该数值大一丁点的最小误差值,该值也被称为机器极小值(epsilon)或最小单元取整数,是计算中所能接受的最小的差别值,举例:
<?php
//$a 和 $b 在小数点后五位精度内都是相等的
$a = 1.23456789;
$b = 1.23456780;
$epsilon = 0.00001;
if(abs($a-$b) < $epsilon) {
echo "true";
}
2.2.4 String 字符串
PHP的string类型是由一系列的字符数组组成的。
一个字符串可以用以下4种方式表示:
单引号
echo 'this is a simple string';
$str = 'this is a simple string, too';
双引号
如果字符串是包围在双引号(")中, PHP 将对一些特殊的字符进行解析(链接)
echo "this is a simple string\n";
$str = "this is a simple string, too";
Heredoc 结构
heredoc 句法结构:<<<
在该运算符之后要提供一个标识符,然后换行。接下来是字符串 string 本身,最后要用前面定义的标识符作为结束标志。
结束时所引用的标识符必须在该行的第一列,而且,标识符的命名也要像其它标签一样遵守 PHP 的规则:只能包含字母、数字和下划线,并且必须以字母和下划线作为开头。
示例:
$str = <<<EOD
这是一段
使用heredoc语法实现的
多行字符串赋值
EOD;
Nowdoc 结构
注意: 只有PHP版本>=5.3.0时才支持此结构。
就象 heredoc 结构类似于双引号字符串,Nowdoc 结构是类似于单引号字符串的。Nowdoc 结构很象 heredoc 结构,但是 nowdoc 中不进行解析操作。这种结构很适合用于嵌入 PHP 代码或其它大段文本而无需对其中的特殊字符进行转义。与 SGML 的 <![CDATA[ ]]> 结构是用来声明大段的不用解析的文本类似,nowdoc 结构也有相同的特征。
一个 nowdoc 结构也用和 heredocs 结构一样的标记 <<<, 但是跟在后面的标识符要用单引号括起来,即 <<<'EOT'。Heredoc 结构的所有规则也同样适用于 nowdoc 结构,尤其是结束标识符的规则。
示例:
$str = <<<'EOD'
这是一段
使用nowdoc语法实现的
多行字符串赋值
EOD;
变量解析
当字符串用双引号或 heredoc 结构定义时,其中的变量将会被解析。
2.2.5 Array 数组
PHP 中的数组实际上是一个有序映射。映射是一种把 values 关联到 keys 的类型。此类型在很多方面做了优化,因此可以把它当成真正的数组,或列表(向量),散列表(是映射的一种实现),字典,集合,栈,队列以及更多可能性。由于数组元素的值也可以是另一个数组,树形结构和多维数组也是允许的。
数组定义
可以用 array() 语言结构来新建一个数组。它接受任意数量用逗号分隔的 键(key) => 值(value)对。
array(
key => value,
...
)
// 键(key)可是是一个整数 integer 或字符串 string
// 值(value)可以是任意类型的值
最后一个数组单元之后的逗号可以省略。通常用于单行数组定义中,例如常用 array(1, 2) 而不是 array(1, 2, )。对多行数组定义通常保留最后一个逗号,这样要添加一个新单元时更方便。
自 5.4 起可以使用短数组定义语法,用 [] 替代 array()。
示例:
$array = array(
"foo" => "bar",
"bar" => "foo",
);
//PHP5.4起支持的语法
$array = [
"foo" => "bar",
"bar" => "foo",
];
key 可以是 integer 或者 string。value 可以是任意类型。
数组key的一些注意事项:
包含有合法整型值的字符串会被转换为整型。例如键名 "8" 实际会被储存为 8,但是 "08" 则不会强制转换,因为其不是一个合法的十进制数值。
浮点数也会被转换为整型,意味着其小数部分会被舍去。例如键名 8.7 实际会被储存为 8。
布尔值也会被转换成整型。即键名 true 实际会被储存为 1 而键名 false 会被储存为 0。
Null 会被转换为空字符串,即键名 null 实际会被储存为 ""。
数组和对象不能被用为键名。坚持这么做会导致警告:Illegal offset type。如果在数组定义中多个单元都使用了同一个键名,则只使用了最后一个,之前的都被覆盖了。
2.2.6 Object 对象
要创建一个新的对象 object,使用 new 语句实例化一个类即可。
示例:
class foo {
function do_foo() {
echo "Doing foo.";
}
}
$bar = new foo;
$bar->do_foo();
2.2.7 Resource 资源类型
资源 resource 是一种特殊变量,保存了到外部资源的一个引用。资源是通过专门的函数来建立和使用的。
由于资源类型变量保存有为打开文件、数据库连接、图形画布区域等的特殊句柄,因此将其它类型的值转换为资源没有意义。
NULL
特殊的 NULL 值表示一个变量没有值。NULL 类型唯一可能的值就是 NULL。
NULL 类型只有一个值,就是不区分大小写的常量 NULL。
在下列情况下一个变量被认为是 NULL:
被赋值为 NULL
尚未被赋值
被 unset()
使用 (unset) $var
将一个变量转换为 null
将不会删除该变量或 unset
其值。仅是返回 NULL
值而已。
2.3 PHP变量
2.3.1 变量基础
PHP 中的变量用一个美元符号后面跟变量名来表示。变量名是区分大小写的。
变量名与 PHP 中其它的标签一样遵循相同的规则。一个有效的变量名由字母或者下划线开头,后面跟上任意数量的字母,数字,或者下划线。按照正常的正则表达式,它将被表述为:'a-zA-Z_\x7f-\xff*'。
提示:$this 是一个特殊的变量,它不能被赋值。
示例:
$var = 'Bob';
$Var = 'Joe';
变量默认总是传值赋值。那也就是说,当将一个表达式的值赋予一个变量时,整个原始表达式的值被赋值到目标变量。这意味着,例如,当一个变量的值赋予另外一个变量时,改变其中一个变量的值,将不会影响到另外一个变量。
PHP 也提供了另外一种方式给变量赋值:引用赋值。这意味着新的变量简单的引用(换言之,“成为其别名” 或者 “指向”)了原始变量。改动新的变量将影响到原始变量,反之亦然。
使用引用赋值,简单地将一个 &
符号加到将要赋值的变量前(源变量)。
虽然在 PHP 中并不需要初始化变量,但对变量进行初始化是个好习惯。未初始化的变量具有其类型的默认值 - 布尔类型的变量默认值是 FALSE,整形和浮点型变量默认值是零,字符串型变量默认值是空字符串以及数组变量的默认值是空数组。
依赖未初始化变量的默认值在某些情况下会有问题,例如把一个文件包含到另一个之中时碰上相同的变量名。另外把 register_globals 打开是一个主要的安全隐患。使用未初始化的变量会发出 E_NOTICE 错误,但是在向一个未初始化的数组附加单元时不会。isset() 语言结构可以用来检测一个变量是否已被初始化。
2.3.2 预定义变量
PHP 提供了大量的预定义变量。由于许多变量依赖于运行的服务器的版本和设置,及其它因素,所以并没有详细的说明文档。一些$_SERVER相关的预定义变量在 PHP 以命令行形式运行时并不生效。
2.3.3 变量作用域
变量的范围即它定义的上下文背景(也就是它的生效范围)。大部分的 PHP 变量只有一个单独的范围。这个单独的范围跨度同样包含了 include 和 require 引入的文件。如下,这里变量 $a 将会在包含文件 b.inc.php 中生效:
$a = 1;
include 'b.inc.php';
在用户自定义函数中,一个局部函数范围将被引入。任何用于函数内部的变量按缺省情况将被限制在局部函数范围内。例如:
$a = 1;
function test() {
echo $a;
}
test(); //打印空字符串
这个脚本不会有任何输出,因为 echo 语句引用了一个局部版本的变量 $a,而且在这个范围内,它并没有被赋值。你可能注意到 PHP 的全局变量和 C 语言有一点点不同,在 C 语言中,全局变量在函数中自动生效,除非被局部变量覆盖。这可能引起一些问题,有些人可能不小心就改变了一个全局变量。PHP 中全局变量在函数中使用时必须声明为 global。
global 关键字
$a = 1;
$b = 2;
function sum() {
global $a, $b;
$b = $a + $b;
}
sum();
echo $b;
以上脚本的输出将是 3
。在函数中声明了全局变量 $a
和 $b
之后,对任一变量的所有引用都会指向其全局版本。对于一个函数能够声明的全局变量的最大个数,PHP 没有限制。
在全局范围内访问变量的第二个办法,是用特殊的 PHP 自定义 $GLOBALS
数组。前面的例子可以写成:
$a = 1;
$b = 2;
function sum() {
$GLOBALS['b'] = $GLOBALS['a'] + $GLOBALS['b'];
}
sum();
echo $b;
$GLOBALS
是一个关联数组,每一个变量为一个元素,键名对应变量名,值对应变量的内容。$GLOBALS
之所以在全局范围内存在,是因为 $GLOBALS
是一个超全局变量。
静态变量
变量范围的另一个重要特性是静态变量(static variable)。静态变量仅在局部函数域中存在,但当程序执行离开此作用域时,其值并不丢失。
function test() {
static $a = 0;
echo $a;
$a++;
}
变量 $a
仅在第一次调用 test()
函数时被初始化,之后每次调用 test()
函数都会输出 $a
的值并加一。
静态变量也提供了一种处理递归函数的方法。递归函数是一种调用自己的函数。写递归函数时要小心,因为可能会无穷递归下去。必须确保有充分的方法来中止递归。
可变变量
有时候使用可变变量名是很方便的。就是说,一个变量的变量名可以动态的设置和使用。一个普通的变量通过声明来设置,例如: $a = 'hello';
。
一个可变变量获取了一个普通变量的值作为这个可变变量的变量名。在上面的例子中 hello 使用了两个美元符号($)以后,就可以作为一个可变变量的变量了。例如: $$a = 'world';
。
这时,两个变量都被定义了:$a 的内容是“hello”并且 $hello 的内容是“world”。
要将可变变量用于数组,必须解决一个模棱两可的问题。这就是当写下 $$a[1]
时,解析器需要知道是想要 $a[1]
作为一个变量呢,还是想要 $$a
作为一个变量并取出该变量中索引为 [1]
的值。解决此问题的语法是,对第一种情况用 ${$a[1]}
,对第二种情况用 ${$a}[1]
。
类的属性也可以通过可变属性名来访问。可变属性名将在该调用所处的范围内被解析。例如,对于 $foo->$bar
表达式,则会在本地范围来解析 $bar
并且其值将被用于 $foo
的属性名。对于 $bar
是数组单元时也是一样。
注意:
在 PHP 的函数和类的方法中,超全局变量不能用作可变变量。
$this 变量也是一个特殊变量,不能被动态引用。
外部变量
HTTP (POST 和 GET)
当一个表单提交给 PHP 脚本时,表单中的信息会自动在脚本中可用。
form表单:
<form action="foo.php" method="POST">
Name: <input type="text" name="username"><br />
Email: <input type="text" name="email"><br />
<input type="submit" name="submit" value="Submit me!" />
</form>
PHP脚本:
echo $_POST['username'];
echo $_REQUEST['username'];
使用 GET 表单也类似,只不过要用适当的 GET 预定义变量。GET 也适用于 QUERY_STRING(URL 中在“?”之后的信息)。因此,举例说,http://www.example.com/test.php?id=3 包含有可用 $_GET['id']
来访问的 GET 数据。
HTTP Cookies
PHP 透明地支持 RFC 6265
定义中的 HTTP cookies,Cookies 是一种在远端浏览器端存储数据并能追踪或识别再次访问的用户的机制。可以用 setcookie()
函数设定 cookies,Cookies 是 HTTP 信息头中的一部分,因此 SetCookie 函数必须在向浏览器发送任何输出之前调用。对于 header()
函数也有同样的限制。Cookie 数据会在相应的 cookie 数据数组中可用,例如 $_COOKIE
,$HTTP_COOKIE_VARS
和 $_REQUEST
。
如果要将多个值赋给一个 cookie 变量,必须将其赋成数组。如下:
setcookie("MyCookie[foo]", 'Testing 1', time()+3600);
setcookie("MyCookie[bar]", 'Testing 2', time()+3600);
这将会建立两个单独的 cookie,尽管 MyCookie 在脚本中是一个单一的数组。如果想在仅仅一个 cookie 中设定多个值,考虑先在值上使用 serialize()
或 explode()
。
注意在浏览器中一个 cookie 会替换掉上一个同名的 cookie,除非路径或者域不同。
确定变量类型
因为 PHP 会判断变量类型并在需要时进行转换(通常情况下),因此在某一时刻给定的变量是何种类型并不明显。
PHP 包括几个函数可以判断变量的类型,例如:gettype()
,is_array()
,is_float()
,is_int()
,is_object()
和 is_string()
。