# 一页纸 PHP 手册

基于 Learn X in Y minutes (opens new window) 进行修改

# 基本结构

<?php // PHP的代码必须包围在 <?php ? > 之中
// 但是如果文件中只有php代码, 那么建议省略结束括号标记 ? >

// (每个语句必须以分号结尾)

1
2
3
4
5

# 注释

// PHP 的注释追随 C 语言的传统, 和 C 语言、JavaScript 是一样的

// 这是单行注释

/*
这是多行注释
*/
1
2
3
4
5
6
7

# 输入输出

# 输出

// 使用 "echo" 或者 "print" 来输出信息
print('Hello World!');  //输出 "Hello World!" 并且没有换行符
print('Hello World!\n');  //输出 "Hello World!" 并且换行

echo "Hello World!\n"; // 输出 "Hello World!" 并且换行

// 在 <?php 标签之外的语句都被自动输出
?>Hello World
<?php

// 实际上, echo和print属于PHP语言本身, 所以我们可以省略括号
echo 'Hello World!';
print 'Hello World!'; 


$paragraph = 'paragraph';
echo 100;        // 直接输出标量
echo $paragraph; // 或者输出变量


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 嵌入网页

<html>
	<body>
		<!-- 使用 script 来嵌入 JavaScript 脚本 -->
		<script>
			alert("客户端时间" + (new Date()));
		</script>

		<!-- 使用 "<?php   ?>" 来嵌入 PHP 脚本 -->
		<?php
			echo "服务器时间".date("Y-m-d H:i:s")."<br>";
		?>
	</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13

# 变量

# 变量命名

// 变量以$开始
// 变量名可以以字母或者下划线开头, 后面可以跟着数字、字母、下划线
// 一般来说, 以下划线开头的变量是有特殊含义的变量, 一般不要使用

// 错误的变量名:
a
$1a
$a1$
$a1-1

// 正确的变量名:
$a
$_a
$a1
$a1_
$A1H_

// 变量名对字母大小写敏感, 也就是说, 大小写不同就是不同的变量
// $about 和 $About 是两个不同的变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 变量赋值 / 声明变量

// 变量的赋值
$x = 1; // 把 1 赋值给 $x
$y = 2;
$x = $y; // 把 $y 的值(当前是2), 赋值给 $x; 之后, 改变 $y 的值不会影响 $x

// 引用赋值
$z = &$y; // $z 当前是 $y 的引用, 也就是说, 更改 $z 的值也会更改 $y 的值, 反之亦然; 但是改变 $y 的值不会改变 $x 的值

echo $x; // => 2
echo $z; // => 2
$y = 0;
echo $x; // => 2
echo $z; // => 0


$a = $b = $c = 3; // 同时声明多个变量
echo $a; // 3
echo $b; // 3
echo $c; // 3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 变量类型转换

// 自动转换
// 变量可以根据其使用情况自动进行类型转换! 这个功能很方便, 但是也是各种错误的来源

$integer = 1;
echo $integer + $integer; // => 2

$string = '1';
echo $string + $string; // => 2 (字符串在此时被转化为整数)

$string = 'one';
echo $string + $string; // => 0
// 输出0, 因为'one'这个字符串无法被转换为整数

// 类型转换可以将一个类型视作另一种类型
$boolean = (boolean) 1; // => true

$zero = 0;
$boolean = (boolean) $zero; // => false


// 强制类型转换
$str = "123.45abc";
$int = intval($str);  //123
$flo = floatval($str); //123.45
$str = strval(123.45); //"123.45"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 常量

// 常量
// 常量前面没有美元符号 $
// 常量只能使用 define() 函数定义, 而不能通过赋值定义
// 常量一旦被定义, 就不能被修改或者取消, 直到脚本运行结束
// 常量的值只能是整数型、浮点型、字符串、布尔值中的一种, 不能是数组、对象
define("FA", 100);
echo FA * 5; //500

// 常见的常量:
TRUE; // 布尔值, 真
FALSE; // 布尔值, 假
NULL; // 空值
DIRECTORY_SEPARATOR; //根据操作系统的不同, 决定的目录分隔符, \ 或者 /
1
2
3
4
5
6
7
8
9
10
11
12
13

# 魔术常量

__FILE__;  // 当前的文件名
__LINE__;  // 当前的行数
__FUNCTION__; // 当前的函数名
__CLASS__; // 当前的类名
__METHOD__; // 当前对象的方法名
1
2
3
4
5

# 数据类型

# 布尔值

// 布尔值 boolean, 就是“真”和“假”
// 布尔值很特别, 对大小写不敏感, 可以是 True 或是 TRUE 或是 true
$boolean = true;  // 或 TRUE 或 True
$boolean = false; // 或 FALSE 或 False


/*
下面的值被认为是“假 / False":
- 布尔值: False
- 整数型: 0 为“假”, 其他所有非零的都为“真”
- 浮点型: 0.0
- 字符串: 空白字符和空白字符串为 “假”
- 数组: 没有成员变量的数组为“假”
- 对象: 没有单元的对象
- null: null 被认为是“假”


*/
// , 
// 
// 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 整数型

// 整数型 integer
$int1 = 12;   // => 12
$int2 = -12;  // => -12
$int3 = 012;  // => 10 (0开头代表八进制数)
$int4 = 0x0F; // => 15 (0x开头代表十六进制数)
1
2
3
4
5

# 小数型 / 浮点型

// 浮点型 float (即双精度浮点型, 可以简单理解为小数)
$float = 1.234;
$float = 1.2e3;
$float = 7E-10;

1
2
3
4
5

# 字符串

// 字符串 string
$str = "Hello";

// 注意: 可以使用单引号或者双引号来包裹字符串, 但是
// 只有双引号里面的变量和转义字符才能生效
$a = "Hello";
$str1 = "$a, World"; // 输出 Hello, World
$str2 = '$a, World'; // 输出 $a, World
1
2
3
4
5
6
7
8

# NULL

// 空值 null
$var = null;
$var = NULL;

// 下列变量被认为是 null:
// - 直接赋值 null
// - 声明的变量尚未被赋值
// - 被 unset() 销毁的变量

1
2
3
4
5
6
7
8
9

# 资源类型

// 是一种特殊类型的变量, 目的是用变量保存对外部资源的引用
// 包括: 打开文件、连接数据库、创建图形画布

// 使用 fopen() 函数以只写的方式打开 info.txt 文件
$file_handle = fopen("info.txt", "w");
var_dump($file_handle);  //  → resource(3) of type (stream)

1
2
3
4
5
6
7

# 操作符

# 操作符: 算数操作符

$sum        = 1 + 1; // 2
$difference = 2 - 1; // 1
$product    = 2 * 2; // 4
$quotient   = 2 / 1; // 2
$mod = 7 % 2; // 1, 取模

// 算数运算的简写
$number = 0;
$number += 1;      // $number 自增1
echo $number++;    // 输出1 (运算后自增)
echo ++$number;    // 输出3 (自增后运算)
$number /= $float; // 先除后赋值给 $number
1
2
3
4
5
6
7
8
9
10
11
12

# 操作符: 逻辑操作符

  • and 或者 &&
  • or 或者 ||
  • not 或者 !

# 操作符: 比较操作符

    • 大于
  • <
    • 小于
  • =

    • 大于等于
  • <=
    • 小于等于
  • ==
    • 等于
  • ===
    • 全等于
    • 要求数据类型也必须相等
  • != 或者 <>
    • 不等于
  • !==
    • 非全等于
$a = 0;
$b = '0';
$c = '1';
$d = '1';


// 下面的比较都为真, 不管它们的类型是否匹配
assert($a == $b); // 相等
assert($c != $a); // 不等于
assert($c <> $a); // 不等于
assert($a < $c);
assert($c > $b);
assert($a <= $b);
assert($c >= $d);

// 下面的比较只有在类型相同、值相同的情况下才为真
assert($c === $d);
assert($a !== $d);
assert(1 === '1');
assert(1 !== '1');

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 操作符: 字符串的操作符

// 使用 . 连接字符串
echo 'This string ' . 'is concatenated';

// 字符串必须包裹在单引号和双引号之中
$sgl_quotes = '$String'; // => '$String'
$sgl_quotes = "$String"; // => '$String'

// 如果需要在字符串中引用变量, 就必须使用双引号
$dbl_quotes = "This is a $sgl_quotes."; // => 'This is a $String.'

// 转义字符只有在双引号中有效
$escaped   = "This contains a \t tab character.";
$unescaped = 'This just contains a slash and a t: \t';

// 可以把变量包含在一对大括号中
$money = "I have $${number} in the bank.";

// 自 PHP 5.3 开始, nowdocs 可以被用作多行非计算型字符串
$nowdoc = <<<'END'
Multi line
string
END;

// 而Heredocs则可以用作多行计算型字符串
$heredoc = <<<END
Multi line
$sgl_quotes
END;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 操作符: 优先级

  • 简单来说:
    • 自增自减操作符 > ! > 算术操作符 > 比较操作符 > (字符) 逻辑操作符 > 赋值操作符 > (语义) 逻辑操作符
  • "(字符) 逻辑操作符"是指 && ||, 但是注意, 逻辑非 ! 的优先级非常靠前
  • "(语义) 逻辑操作符"是指 not and or

# 容器

# 数组

// PHP 中的数组都是关联型数组, 也就是Python的"字典"和C语言的“哈希表”
$associative = array('One' => 1, 'Two' => 2, 'Three' => 3);
$associative2 = ['One' => 1, 'Two' => 2, 'Three' => 3];

echo $associative['One']; // 输出 1
echo $associative2['One']; // 输出 1
1
2
3
4
5
6

# 列表

// 列表
$array = ['One', 'Two', 'Three'];

// “列表”本质上是分配了整数键的“数组”
$array = ['One', 'Two', 'Three'];
echo $array[0]; // => "One"
1
2
3
4
5
6

# 对象

// 对象由一组属性值和一组方法组成
class Person {
	var $name;
	
	function say() {
		echo "Hi"
	}
}

$p = new Person;

$p->name = "Mike";
$p->say();
1
2
3
4
5
6
7
8
9
10
11
12
13

# 流程控制

# 流程控制: 判断

//常见的判断流程
if (true) {
    print 'I get printed';
}

if (false) {
    print 'I don\'t';
} else {
    print 'I get printed';
}

if (false) {
    print 'Does not get printed';
} elseif(true) {
    print 'Does';
}



// 三元运算符
print (false ? 'Does not get printed' : 'Does');



$x = 0;
if ($x === '0') {
    print 'Does not print';
} elseif($x == '1') {
    print 'Does not print';
} else {
    print 'Does print';
}



// 下面的语法常用于网页中:
<?php if ($x): ?>
This is displayed if the test is truthy.
<?php else: ?>
This is displayed otherwise.
<?php endif; ?>



// switch分支
switch ($x) {
    case '0':
        print 'Switch does type coercion';
        break; // 在case中必须使用一个break语句, 
               // 否则在执行完这个语句后会直接执行后面的语句
    case 'two':
    case 'three':
        // 如果$variable是 'two' 或 'three', 执行这里的语句
        break;
    default:
        // 其他情况
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

# 流程控制: 循环

// while 循环
$i = 0;
while ($i < 5) {
    echo $i++;
}; // 输出 "01234"

echo "\n";


// do...while 循环
$i = 0;
do {
    echo $i++;
} while ($i < 5); // 输出 "01234"

echo "\n";



//  for 循环
for ($x = 0; $x < 10; $x++) {
    echo $x;
} // 输出 "0123456789"

echo "\n";



// foreach 循环
// 可以遍历数组
$wheels = ['bicycle' => 2, 'car' => 4];
foreach ($wheels as $wheel_count) {
    echo $wheel_count;
} // 输出 "24"

// foreach 循环也可以同时遍历"键"和"值"
foreach ($wheels as $vehicle => $wheel_count) {
    echo "A $vehicle has $wheel_count wheels";
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

# 流程控制: 跳过循环 & 退出循环

// break 退出循环
$i = 0;
while ($i < 5) {
    if ($i === 3) {
        break; // 退出整个循环
    }
    echo $i++;
} // 输出 "012"


// continue 跳过本次循环
for ($i = 0; $i < 5; $i++) {
    if ($i === 3) {
        continue; // 跳过此次遍历
    }
    echo $i;
} // 输出 "0124"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 流程控制: 异常


1

# 组织代码

# 组织代码: 函数

// 通过"function"定义函数:
function my_function () {
  return 'Hello';
}
echo my_function(); // => "Hello"


// 函数名的命名规则和变量名类似, 但不能以 $ 开头
// 而是需要以字母或者下划线开头, 后面可以跟着任意的数字、字母、下划线
function add ($x, $y = 1) { // $y 是可选参数, 默认值为 1
  $result = $x + $y;
  return $result;
}

echo add(4); // => 5
echo add(4, 2); // => 6


// $result 在函数外部不可访问
// print $result; // 抛出警告


// 匿名函数
// 从 PHP 5.3 起我们可以定义匿名函数
$inc = function ($x) {
  return $x + 1;
};

echo $inc(2); // => 3

function foo ($x, $y, $z) {
  echo "$x - $y - $z";
}


// 函数也可以返回一个函数
function bar ($x, $y) {
  // 用 'use' 将外部的参数引入到里面
  return function ($z) use ($x, $y) {
    foo($x, $y, $z);
  };
}

$bar = bar('A', 'B');
$bar('C'); // 输出 "A - B - C"

// 你也可以通过字符串调用函数
$function_name = 'add';
echo $function_name(1, 2); // => 3
// 在通过程序来决定调用哪个函数时很有用
// 或者, 使用 call_user_func(callable $callback [, $parameter [, ... ]]);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

# 组织代码: 类 & 对象

// 类是由class关键字定义的

class MyClass
{
    const MY_CONST      = 'value'; // 常量

    static $staticVar   = 'static';

    // 属性必须声明其作用域
    public $property    = 'public';
    public $instanceProp;
    protected $prot = 'protected'; // 当前类和子类可访问
    private $priv   = 'private';   // 仅当前类可访问

    // 通过 __construct 来定义构造函数
    public function __construct($instanceProp) {
        // 通过 $this 访问当前对象
        $this->instanceProp = $instanceProp;
    }

    // 方法就是类中定义的函数
    public function myMethod()
    {
        print 'MyClass';
    }

    final function youCannotOverrideMe()
    {
    }

    public static function myStaticMethod()
    {
        print 'I am static';
    }
}

echo MyClass::MY_CONST;    // 输出 'value';
echo MyClass::$staticVar;  // 输出 'static';
MyClass::myStaticMethod(); // 输出 'I am static';

// 通过new来新建实例
$my_class = new MyClass('An instance property');
// 如果不传递参数, 那么括号可以省略

// 用 -> 来访问成员
echo $my_class->property;     // => "public"
echo $my_class->instanceProp; // => "An instance property"
$my_class->myMethod();        // => "MyClass"


// 使用extends来生成子类
class MyOtherClass extends MyClass
{
    function printProtectedProperty()
    {
        echo $this->prot;
    }

    // 方法覆盖
    function myMethod()
    {
        parent::myMethod();
        print ' > MyOtherClass';
    }
}

$my_other_class = new MyOtherClass('Instance prop');
$my_other_class->printProtectedProperty(); // => 输出 "protected"
$my_other_class->myMethod();   // 输出 "MyClass > MyOtherClass"

final class YouCannotExtendMe
{
}




// 你可以使用"魔法方法"来生成getter和setter方法
class MyMapClass
{
    private $property;

    public function __get($key)
    {
        return $this->$key;
    }

    public function __set($key, $value)
    {
        $this->$key = $value;
    }
}

$x = new MyMapClass();
echo $x->property; // 会使用 __get() 方法
$x->property = 'Something'; // 会使用 __set() 方法

// 类可以是被定义成抽象类 (使用 abstract 关键字) 或者
// 去实现接口 (使用 implements 关键字).
// 接口需要通过interface关键字来定义

interface InterfaceOne
{
    public function doSomething();
}

interface InterfaceTwo
{
    public function doSomethingElse();
}

// 接口可以被扩展
interface InterfaceThree extends InterfaceTwo
{
    public function doAnotherContract();
}

abstract class MyAbstractClass implements InterfaceOne
{
    public $x = 'doSomething';
}

class MyConcreteClass extends MyAbstractClass implements InterfaceTwo
{
    public function doSomething()
    {
        echo $x;
    }

    public function doSomethingElse()
    {
        echo 'doSomethingElse';
    }
}


// 一个类可以实现多个接口
class SomeOtherClass implements InterfaceOne, InterfaceTwo
{
    public function doSomething()
    {
        echo 'doSomething';
    }

    public function doSomethingElse()
    {
        echo 'doSomethingElse';
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150

# 组织代码: 导入其他 php 文件


<?php
// 被导入的php文件也必须以php开标签开始

include 'my-file.php';
// 现在my-file.php就在当前作用域中可见了
// 如果这个文件无法被导入( 比如文件不存在 ), 会抛出警告

include_once 'my-file.php';
// my-file.php中的代码在其他地方被导入了, 那么就不会被再次导入
// 这会避免类的多重定义错误

require 'my-file.php';
require_once 'my-file.php';
// 和include功能相同, 只不过如果不能被导入时, 会抛出错误


// my-include.php的内容:
<?php

return 'Anything you like.';
// 文件结束

// Include和Require函数也有返回值
$value = include 'my-include.php';

// 被引入的文件是根据文件路径或者include_path配置来查找到的
// 如果文件最终没有被找到, 那么就会查找当前文件夹. 之后才会报错
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 其他

/*
 * 特征
 */

// 特征 从 PHP 5.4.0 开始包括, 需要用 "trait" 这个关键字声明

trait MyTrait
{
    public function myTraitMethod()
    {
        print 'I have MyTrait';
    }
}

class MyTraitfulClass
{
    use MyTrait;
}

$cls = new MyTraitfulClass();
$cls->myTraitMethod(); // 输出 "I have MyTrait"


/********************************
 * 命名空间
 */

// 这部分是独立于这个文件的
// 因为命名空间必须在一个文件的开始处. 

<?php

// 类会被默认的放在全局命名空间中, 可以被一个\来显式调用

$cls = new \MyClass();



// 为一个文件设置一个命名空间
namespace My\Namespace;

class MyClass
{
}

// (或者从其他文件中)
$cls = new My\Namespace\MyClass;

//或者从其他命名空间中
namespace My\Other\Namespace;

use My\Namespace\MyClass;

$cls = new MyClass();

// 你也可以为命名空间起一个别名

namespace My\Other\Namespace;

use My\Namespace as SomeOtherNamespace;

$cls = new SomeOtherNamespace\MyClass();

*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64