回顾PHP的一些基础知识,权当对这么多年学习和使用PHP的提炼和总结。
PHP设计之初作为一门宏定义语言,主要用来处理网页表单,所以被设计为可以内嵌在HTML文件里。为了区分HTML代码,PHP代码块的起始界定标签是<?php,结束标签是?>(PHP5.4版本以后可以使用<?和?>短标签)。对于纯PHP文件,同样需要保留<?php作为起始标识,但建议省略结束的?>标签。
变量/常量
PHP中的变量定义需以美元符号“$”开头,例如: $name = 'tlanyan'
。变量名不支持声明变量类型,大小写敏感。合法的变量名以字母、下划线开头,不能以数字、点、加减乘除等特殊符号开头,但是可以以中文汉字开头。
以下是一些变量的声明以及合法性判断:
$name = "tlanyan"; // 合法 $.name = "tlanyan"; // 非法,不能以点开头 $1234 = "tlanyan"; // 非法,不能以数字开头 $myName = "tlanyan"; // 合法 $my-name = "tlanyan"; // 非法,变量名中不能有减号 $名字 = "tlanyan"; // 合法
常量的定义方式有两种:define和const。常量名中的字母必须全部大写,可以用下划线连接。例如:
define('NAME', 'tlanyan'); // 合法 define('NAME_last', 'tlanyan'); // 非法,字母必须全部大写 define('NAME_2', 'tlanyan'); // 合法 define('NAME_中国', 'tlanyan'); // 合法 define('GENDERS', [ 0 => '女', 1 => '男',]); // define定义常量数组,需要PHP7+ echo NAME; // 无需加$或引号 const NAME = 'tlanyan'; // 合法,但是如果define已经定义了NAME,运行时会报错 const NAME_ADcdd = 'tlanyan'; // 非法,字母必须全部为大写 const GENDERS = [ 0 => '女', 1 => '男', ]; // const定义常量数组,需要PHP5.6+
常量定义后,不能更改和取消。defined可以判断一个常量是否定义,constant函数可以取出常量的值(效果同直接取值)。define和const的主要区别是define可以用在判断语句中,但是const不行。如果你需要灵活的方式定义变量,请使用define,否则都建议用const定义常量。
函数
函数的定义以function关键字开头,后接函数名和参数,以大括号包含的函数体结束。代码的定义形式为:
function foo($arg1, $arg2, ...) { // 函数体 }
函数名的要求同变量名,不能以数字开头,不能包含点、加减乘除符号等特殊符号和字符,但是可以用中文命名。不同于变量,函数名不区分大小写。
函数参数可以没有,也可以有多个。支持默认参数,但是默认参数后不可出现必须传值的参数。对于基本类型,参数默认按值传递,对象和资源默认引用传参。
函数体可以为空,也可以有多个语句。可以return返回值,也可以不返回。如果函数没有返回值,则默认为null。
下面是一些函数的示例:
function printName($name = 'World') { echo "Hello, $name!"; } function printName2(array $names) // array参数约束,需要PHP5.1+ { print_r($names); } function printName3(array $names, callable $filter) // callable参数约束,需要PHP5.4+ { print_r(array_map($filter, $names)); } function sum(...$args) // 可变参数数组,需要PHP5.6+ { return array_sum($args); } function printName4(string $name = 'World') // int, float, bool参数类型提示,需要PHP7+ { echo "Hello, $name!"; } function getGreeting(string $name = 'World') : string // 返回类型声明,需要PHP7+ { return "Hello, $name!"; } function getGreeting2(string $name = null) : ?string // 可空返回类型声明,需要PHP7.1+ { return !$name ? null : "Hello, $name!"; }
注意如果限定传参和返回值是bool类型,应该用bool而不能使用boolean,否则运行会报错。
PHP目前为止不支持重载。一种变相的重载实现方式是: 以 …args 定义函数参数,函数体根据参数个数实现不同功能。
操作符
PHP支持常规算术运算符、赋值运算符、位运算操作符等。以下是一些示例:
$a = 2;$b = 3; echo $a (+|-|*|/|%|**) $b; // 加减乘除、取模、指数 ++$a; --$b; // 自增和自减 $c = $a + $b; // 赋值 $d = $a (&,|,^,<<, >>) $b; // 并、或、异或、左移和右移位运算 $e = ~$a; // 取反 echo $a (==|===|!=|<>|<|>|<=|>=|<=>) $b; // 比较运算符:相等、全等、不等、不等、小于、大于、小于等于、大于等于、太空符(需要PHP7+) $str1 = 'Hello'; $str2 = 'World'; echo $str1 . ',' . $str2 . '!'; // . 作为字符串连接符 if ($a (|| , && , xor , and, or) !$b) {} // 逻辑运算符:或、并、异或、并、或、非 $arr1 = [1, 2]; $arr2 = [3, 4]; print_r($arr1 + $arr2); // 数组合并 var_dump($arr1 !=|!==|<>|==|=== $arr2); // 数组比较 var_dump($arr1 instanceof int); // instanceof操作符 @coun($arr1); //错误控制符@。当@加在函数调用前,函数抛出的错误将被忽略 var_dump(`ls -al`); // ``, 非单引号, shell执行符号
流程控制
PHP支持常见的分支判断、循环等流程控制。以下是一些示例:
$array = range(0, 10); $length = count($array); if ($length > 20) { // if/elseif/else控制符 echo '>= 20'; } elseif ($length < 10) { echo '< 10'; } else { echo '10<= length < =20'; } $index = 0; while ($index < $length) { // while循环、continue、break if ($index % 2 === 0) { continue; } echo $array[$index], PHP_EOL; ++ $index; if ($index == 9) { break; } } $index = 0; // do-while循环 do { echo $array[$index], PHP_EOL; ++ $index; } while ($index < $length); for ($index = 0; $index < $length; ++ $index) { // for循环 echo $array[$index], PHP_EOL; } foreach ($array as $value) { // foreach循环 echo $value, PHP_EOL; } switch ($length) { // switch case 1: case 3: case 10: echo 'A'; break; case 4: case 5: echo 'B'; break; default: break; }
类/接口/名字空间/特性
PHP5.3增加了名字空间和静态延迟绑定,PHP5.4增加了特性(trait)功能,标志着PHP对面向对象编程的支持进了一大步。
类
类在基本类型和数组上进行了拓展,丰富了编程中的类型,同时让开发人员有能力在更高层次上对问题进行建模。
PHP用class关键字对类进行定义,类中可包含属性变量、属性常量、行为方法和特性。以下是定义和使用类的示例:
class People { // 定义一个类 const MALE = 1; const FEMALE = 0; // 类常量 private $age; // 私有属性 public $gender; // 共有属性 public $name; // 共有属性 public __construct($name, $gender = People::MALE) // 构造函数,类常量作为默认参数,需要PHP5.6+ { $this->name = $name; $this->gender = $gender; } public function getAge() // 共有方法 { if ($age < 16) { return $this->age + 2; } if ($age > 35) { return $this->age - 3; } return $this->age; } private function sleep() // 私有方法 { ++ $this->age; } public function __toString() { return "People [ name: {$this->name}, gender: {$this->gender}]"; } } $me = new People('tlanyan', People::MALE); // 实例化一个类 echo $me->name; // 获取类的公有属性 echo $me->age; // 非法,外部不能获取类的私有属性 echo $me->getAge(); // 调用公有方法 $me->sleep(); // 非法,外部不能调用私有方法 echo $me; // 调用__toString方法,打印信息
__construct和__toString函数被称为“魔术方法”,常用的魔术方法还包括:__get, __set, __clone, __call等。当对类的对象发送消息时,这些魔术方法赋予拦截的机会,从而做出响应。
接口
编程中很重要的一个原则是面向接口编程,而非面向实现编程。接口规定了实现接口时必须遵守的规则,屏蔽了具体的实现细节。在与其它层交互是,只需要按照既定义的规则对接即可,从而达到解耦的目的。
在PHP中用interface关键字定义接口,接口包含的规则同定义类的成员函数相似,但是接口不能包含成员属性、常量等。以下是一个接口定义和实现:
class Message { public $id; public $content; public $create_at; } interface Notify { public void notify(Message msg); } class SmsNotify implements Notify { public void notify(Message msg) { // send message using the carrier api } }
接口中只包含规则的签名,具体实现由实现类负责。一个实现类可以同时实现多个接口。
名字空间
为了更好的组织程序代码,也为了避免类名和方法名重复,PHP在5.3版本中增加了对名字空间的支持。名字空间用namespace定义,层次用反斜杠/来分割。名字空间定义必须出现在文件的非注释第一行。以下是名字空间的示例:
// 文件名: Foo.php namespace tlanyan; // 定义名字空间,以下定义均位于该名字空间内 const VERSION = '1.0-SNAPSHOT'; // 定义名字空间常量 function greeting() { // 定义名字空间函数 echo 'you are calling functions in namespace tlanyan'; } class Foo { // 定义名字空间中的类 } // 在另外一个文件内使用以上定义的内容 require ('Foo.php'); use tlanyan; // 申明使用tlanyan名字空间中 use tlanyan/Foo; // 引入Foo类 echo tlanyan/VERSION; // 调用名字空间中的常量 /tlanyan/greeting(); // 使用完全限定名字空间方式调用函数 $foo = new Foo(); // 调用名字空间中的类
特性
特性(trait)是为了复用程序代码,在PHP5.4中增加的新功能。PHP不能使用多继承,但是可以将一些常用的功能抽取出来做成trait,然后包含到多个类中,达到代码复用的目的。
特性用关键字trait声明,可以包含属性和方法,但不能包含常量。下面是一个示例:
trait Log { public function log(string $message, string $category) { $line = "[$category]" . date('Y-m-d H:i:s') . " $message"; file_put_contents('/tmp/log.txt', $line, FILE_APPEDN); } } class Foo { use Log; // 将特性引入 } $foo = new Foo(); $foo->log('demo', 'application'); // 调用特性中的方法,行为如同类的成员