所有脚本语言都有共通之处,更宽泛的,所有编程语言都有共通的地方,比如变量、函数、类的概念在很多语言里都有。
对脚本语言来说,变量无类型是一个非常普遍的特点,PHP也是如此。下面列出PHP的语言语法特点,可以供初学者快速查询和了解这门语言的语法特点。
- PHP变量前面必须加一个“$”字符,这给打字造成了很大的麻烦,敲“$”字符远比一般字母数字麻烦,因为需要按Shift键。但这是PHP这门语言的特点决定的,PHP灵活的嵌入HTML页面,字符串里面直接解析变量等方式,让这种约定有内在的道理,我们只需要知道这个规则就可以了。
- PHP的变量在全局和局部不能用var声明,但是在作为类的成员变量可以,所以在不能使用var声明变量但是还需要声明的时候,只能用“$a = null;$b = 0;”这样的方式来代替声明。PHP在发明之初可能没有类的定义,所以语言编写者认为声明没有必要,但是引进类之后,声明变量是必须的,所以才引入了“var” 关键字,但是仅用于类这个新加的功能(此为推测)。
的var $a; //错误 class A{ var $a; //正确 } function abc(){ var $a; //错误 $a = "abc"; return $a; }
- 类的语法: 类里面的变量声明时的var好像是必须的, 否则会报语法错误, 可以用public, protected或者private指定访问权限, 而使用了权限限定符号时一定不能用再用var. PHP继承的关键字是extends, 和Java相同, 而不是C++的冒号. PHP类成员变量可以在声明的时候赋值, 这个确实非常方便, C++咋就不行呢? 非要到构造函数里面去写初始化值.
- PHP大小写不敏感,PHP发明人之前是不是用惯了VB?PHP使用大量的内置函数,这侧面说明,PHP是应用层面的编程语言,底层还是用C来实现更好。
- 和JavaScript相同,PHP用function关键字声明一个函数,对无类型语言来说,不用管返回值的类型,也不用管参数的类型,直接写变量名就行了。在调用函数的时候,PHP函数可以多传参数,但是不可以少传。
PHP不支持函数重载, 也就是不允许名称相同, 参数不同的函数, 包括类成员函数.function abc($a){ echo $a; } abc("abc","def");//合法调用 abc(); //非法调用,语法错误。
- PHP的变量可以分为2大类,一个是内置的基本类型:数字、字串、数组,另一个是自定义的类变量。前者,包括数组,使用的赋值的时候都是拷贝复制,所以需要考虑效率问题,特别是数组,没有必要就不要赋给另一个变量。但是还有一点,拷贝只发生在需要对被赋值变量进行写入更改的时候,如果没有这种需求,复制并不会引起拷贝操作。这很好理解,就是一种内部的优化机制,比如一个数组,赋值给另一个变量,如果不对被赋值的变量添加删除更改元素,仅仅是读取,拷贝就不会发生。对于类变量,全部是引用,所有变量都指向同一个对象,要复制一个类对象使用clone函数。
$obj1将会是$obj的一个副本。可以在定义类的时候指定一个__clone成员函数,克隆操作时将被自动调用。$obj1 = clone $obj;
- PHP的变量本质上都是指针, 可能指向一个对象, 也可能什么都不指向, 这时候它的值就是null. 不同的变量也可以指向同一个对象, 这种情况使用“&”操作符,语法如下:
上述情形, 所有对$b的操作, 和对$a执行是一样的. 唯一的一个特殊操作是unset. unset函数的作用是解除变量绑定的对象, 对$b的unset调用, 仅仅是解除$b对对象的引用, 而$a仍然指向那个对象. 也就是说, 除了unset函数, 其它PHP的操作都是针对变量指向的对象的, 只有这个函数的操作是指向变量本身. unset还有一个作用, 是删除一个数组的元素. 变量实际上一般涉及两个部分, 一个是变量本身, 一个是变量指向的对象. 在C语言里面, 变量本身称为指针, 但是大多脚本语言没有明确指针的概念, 而是让使用者记住一些规则, 我个人总是倾向于要搞清这些规则的内在实质. 如果我们直接写一个语句: new A; 这样就在内存中创建了一个A的实例, 但是因为没有对应的变量来指向它, 这个对象永远无法访问, 在C语言中, 这种调用会造成内存泄漏, 在自动清理语言中, 这个实例在不确定的时机, 会被自动清除. PHP一般的操作, 实际上都是针对变量指向的内容, 而不是变量本身, 除了取地址操作"&", 把变量指向一个对象, unset函数, 把对象指向置为空. 实际上还有一个特殊操作, 就是global声明变量.$a = "abc"; $b = $a; $b = "def"; echo $a; //输出"abc",因为$a和$b是独立的两个变量,改变$b不会影响到$a. $b = &$a; $b = "def"; echo $a; //输出"def",因为$a和$b对应同一个变量,改变$b也就改变了$a.
- PHP的全局变量在函数内引用的时候, 需要先用global声明, 否则, 因为PHP变量无需声明, 函数内的同名变量将被认为是一个局部变量. 这一点是很特殊的, 大多数编程语言的全局变量可以在任何地方直接使用. 还有一点,使用global在函数内部引用一个全局变量的时候, 实际操作是创建了一个局部变量, 然后让这个局部变量指向那个(同名)全局变量的对象, 但它不是那个全局变量.
- 高级编程语言一般集成了具有集合功能的对象, 对PHP而言, 这个功能是用数组来做的. 初始化一个数组, 使用" $a = array();", 这样$a成为一个元素为空的数组, 使用count($a)来取得数组的元素个数. PHP的数组下表, 不仅可以是数字, 还可以是字串. 可以用下面的语句初始化一个数组, 并且指定下标:
$a = array("a"=>"A","b"=>"B","c"=>"C");
此时访问$a的元素必须用下面的方式$a["a"], $a["b"]... , 不能再用$a[0], $a[1]...这样的方式. 如果不指定key(下标), 则数组默认key是0,1,2,.... 比如:
$a = array("A","B","C"); echo $a[0] . $a[1] . $a[2];//输出:ABC 。
给数组添加元素,直接赋值就可以,比如:$a = array(); $a["a"] = "A";//这样数组$a就添加了一个元素"A", 访问的key是"a". unset($a["a"]);//元素"A"被移除了.
可以用foreach遍历数组:$a = array("a"=>"A","b"=>"B","c"=>"C"); foreach($a as $key=>$value){ echo $key.":".$value.","; } //输出:a:A,b:B,c:C,
如果不需要$key也可以只写$value:$a = array("a"=>"A","b"=>"B","c"=>"C"); foreach($a as $value){ echo $value.","; } //输出:A,B,C,
给数组添加元素的时候必须先初始化变量为一个数组, 否则调用会出错. 调用foreach的时候, 数组对象不能为null, 否则会报错. - 类
class A { private $name; private $age; function __construct($name, $age) { $this->name=$name; $this->age=$age; } function A($name, $age){ $this->name=$name."a"; $this->age=$age."a"; } function __destruct(){ $this->name = ""; $this->age = ""; } function __clone() { echo "clone called"; } function say() { echo "name:".$this->name."<br />"; echo "age:".$this->age; } } $p1 = new A("张三", 20); $p2 = clone $p1; $p3 = &$p2; $p3->say(); //输出: //name:张三 //age:20
类可以有构造函数和析构函数, 在旧版本里构造函数是类名, 在新版本里, 是__construct函数, 如果类没有__construct函数, 会把类的同名函数作为构造函数, 否则这个函数不会调用. 一个类只能有一个构造函数, 因为PHP不支持函数重载, 调用new实例化类对象的时候, 参数必须和构造函数对应. 析构函数的存在说明PHP可以在确定的时刻销毁对象, 这和自动垃圾回收机制是不同的.
析构的时机: 局部变量在离开作用域(函数体内)的时候, 对象被销毁, 全局变量在页面执行完成后销毁. 还可以显示的销毁对象, 把对象的任何一个引用赋值null都会导致对象销毁; 使用unset解除对对象的引用, 当没有变量引用一个对象时, 它会被销毁. 这些销毁操作都是即时的, 不需要等待垃圾回收运行(PHP根本没有垃圾回收机制).
PHP调用exit函数后, 页面执行将会结束, 但是析构机制保证析构函数仍然能执行. 和Win32调用了ExitPrecess不同, 后者立即终止程序. 但是如果在析构函数内调用了exit, PHP将会立即终止执行. 析构机制的目的需要保证析构函数能够运行, 所以正常的程序, 不应该使用立即终止程序的方式, 而应该让所有析构函数都执行完成.
类的继承:
class Named_Cart extends Cart { var $owner; function set_owner ($name) { $this->owner = $name; } }
使用extends关键字继承另一个类. 需要注意的是, PHP的继承, 父类的构造和析构函数不会自动调用, 需要在子类的构造和析构函数里显示调用:
parent::__construct();parent::__destruct();
PHP的类还有一些其它有默认行为的函数, 比如__get, __tostring等等. - 函数参数传地址调用 PHP和C的函数调用几乎一样丰富, 不但有默认的传值, 还可以有传地址调用, 语法也和C一样, 使用&符号. 而且返回值也可以是传地址, 这时候需要在函数名的前面加&符号, 而且调用的时候, 也需要在函数名前面加上&符号, 否则就是普通调用. 函数返回值此时不能是地址, PHP的语法不允许return后面跟&$var的方式, 就写return $var就可以了.
function &abc(&$a){ $a = "def"; return $a; } $c = "abc"; //赋值"abc" $b = &abc($c); //参数是传址方式,$a也指向$c指向的字串, 所以函数内部$c被赋值成"def" ,按传址方式返回给$b, 所以$b也指向这个字串. echo $b; //输出"def". $b = "abc"; //把$b赋值为"abc"(目的是检测$c是否变化). echo $c; //输出"abc".