面向对象编程(OOP)是一种计算机编程架构,PHP是一种弱类型的编程语言,可以使用OOP,也可以使用过程化编程。
类:是具有相同属性和服务的一组对象的集合。
对象:用来描述客观事物的一个实体,是类的实例化。
类中的属性和服务是具有访问控制权限的,通过添加关键字public(公有)、protected(受保护的)、private(私有)来实现的。
被定义为公有的成员可以在任何地方被访问;被定义为受保护的成员可以被其自身以及其子类和父类访问;被定义为私有的成员则只能被其定义所在的类访问。
类中的构造函数在每次创建新对象时自动调用,所以非常适合做一些初始化的工作。构造函数能够接收用户传递的参数,即在新建对象时传递给对象的参数。
析构函数则相反,它在对象被销毁之前调用,且不接受任何参数。
构造函数与析构函数都是public属性。
<?php
class A {
public function __construct($name){
echo "Hello,".$name.".\n";
}
public function __destruct(){
echo "Goodbye\n";
}
}
$a = new A("Roshan");
上例代码展示了一个类中的构造与析构函数,运行后会输出两行信息:
[root@localhost class]# php A.php
Hello,Roshan.
Goodbye
在新建对象时传递了参数,构造函数接收参数并输出相关信息;在对象销毁前调用了析构函数,输出‘Goodbye’信息。
Static用来声明类的属性或方法为静态,可以不实例化类而直接访问。
正常声明的属性或方法在类中调用时,使用‘$this’;而静态属性或方法在类中调用时使用‘self::’。
<?php
class A {
static $city;
public function __construct($name){
echo "Hello,".$name.".\n";
}
public static function showCity(){
self::$city = 'BeiJing';
echo "Welcome to ".self::$city."\n";
}
public function __destruct(){
echo "Goodbye\n";
}
}
A::showCity();
调用类中的static类型属性或方法,不需要新建对象,使用“类名::方法名”来进行调用。如果使用新建对象的方法调用static类型,会报一个Notice级的错误。
__toString方法用于一个类被当成字符串时的回应,此方法必须返回一个字符串,否则会发生致命错误。
<?php
class A {
static $city;
public function __construct(){
echo "Hello.\n";
}
public function __toString(){
return "Don't echo me!\n";
}
public static function showCity(){
self::$city = 'BeiJing';
echo "Welcome to ".self::$city."\n";
}
public function __destruct(){
echo "Goodbye\n";
}
}
$a = new A();
echo $a;
输出:
[root@localhost class]# php A.php
Hello.
Don't echo me! Goodbye
在脚本开关写一个长长的包含文件的列表,是不是很烦?没关系,可以使用自动加载类的方法来解决这个问题。
定义一个__autoload()函数,它会在试图使用尚未被定义的类时自动加载该类。通过调用此函数,脚本引擎在PHP出错失败前有了最后一个机会加载所需的类。
<?php
function __autoload($className){
require_once $className.".php";
}
A::showCity();
在脚本B.php中有如上代码,当调用A类中的showCity()方法时,PHP发现并没有加载A类,此时会调用__autoload()方法来进行自动加载后再运行。
注意:使用__autoload()方法需要类名与文件名相匹配才能自动加载。
private属性为私有的属性,按权限控制来讲,只允许定义它的类可以对它进行操作,对外是不可见的。但是如果想要在类的外部操作类中的private属性,也不是没有办法。
设置与获取
通过__set()和__get()方法可以设置和获取类中的private属性。
在对private属性时,__set()方法会被调用。__set()方法接收两个参数,第一个参数表示属性的名称,第二个参数表示属性的值。
当读取private属性时,__get()方法会被调用。__get()方法接收一个参数,表示属性的名称。
<?php
class A {
private $car_type;
private $car_age;
public function __set($name,$value){
$this->$name = $value;
}
public function __get($name){
return $this->$name;
}
}
$a = new A();
$a->car_type = "BMW";
echo $a->car_type;
检测与重置
__isset()方法用来检测private属性是否设置,以及是否为空,当对private属性使用isset()或empty()时会被调用。它接收一个参数,为属性的名称。
__unset()方法用来重置private属性,当对private属性使用unset()时会被调用,它接收一个参数,为属性的名称。
<?php
class A {
private $car_type;
private $car_age;
public function __set($name,$value){
$this->$name = $value;
}
public function __get($name){
return $this->$name;
}
public function __isset($name){
return isset($this->$name);
}
public function __unset($name){
unset($this->$name);
}
}
$a = new A();
$a->car_type = "BMW";
echo isset($a->car_type)?"car_type is set\n":"car_type not set\n";
echo $a->car_type;
有时写代码的过程中可能会将调用的某个类的方法名写错,这时就会出现致命错误,如果不想报PHP的错误,那应该怎么办呢?使用__call()方法或__callStatic()方法。
__call()方法用于在对象中调用一个不可用的方法时被调用。
__callStatic方法,用静态方式调用一个不可用的方法时被调用,需要定义为static类型。
__call()方法和__callStatic()方法都是接收两个参数,分别为方法名和参数数组。
<?php
class A {
public function __call($name,$argu){
echo "Call object method:$name,arguments(".implode(',',$argu).")\n";
}
public static function __callStatic($name,$argu){
echo "Call object method:$name,arguments(".implode(',',$argu).")\n";
}
}
$a = new A();
$a->b('Roshan','Happy new Year');
A::c('qwrd',10);
final关键字用于类和方法的声明,不能用于属性的声明。
如果父类中的方法被声明为final,则子类不可以重写该方法。
如果一个类被声明为final,则不能被继承。
<?php
class A {
final public function funB(){
echo "Class A function funB";
}
}
class B extends A {
public function funB(){
echo "Class B function funB";
}
}
运行结果:
[root@localhost class]# php A.php
PHP Fatal error: Cannot override final method A::funB()
以final声明的类:
<?php
final class A {
public function funB(){
echo "Class A function funB";
}
}
class B extends A {
public function funB(){
echo "Class B function funB";
}
}
运行结果:
[root@localhost class]# php A.php
PHP Fatal error: Class B may not inherit from final class (A)
抽象类使用abstract关键字来声明,抽象类不能被实例化。一个类中至少有一个方法被声明为抽象的,那这个类就必须声明为抽象的。
继承一个抽象类时,子类必须定义父类中的所有抽象方法,同时,这些方法的访问控制权限必须与父类中的相同或更加宽松。
<?php
abstract class A {
abstract protected function funB($arg1,$arg2);
public function sayHi(){
echo "HI";
}
}
class B extends A {
public function funB($arg1,$arg2){
echo "ARG1:$arg1,ARG2:$arg2";
}
}
对象接口使用interface关键字定义,接口中定义的方法都是空的,它只是指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容。
接口中定义的所有方法都必须是公有的,这是接口的特性。接口也可以继承,使用extends操作符。
要实现接口,使用implements操作符,类可以实现多个接口,使用逗号分隔。在实现多个接口时,接口中的方法不能重名。类实现接口中的方法,必须使用和接口中所定义的方法完全一致的方式。
<?php
interface A {
public function funA($name,$age);
public function funB($city);
}
class B implements A {
public function funA($name,$age){
}
public function funB($city){
}
}
PHP中的值都可以使用serialize()函数来返回一个包含字节流的字符串来表示。而unserialize()函数则是重新把字符串变回PHP原来的值。
序列化对象保存的是类的名字。
<?php
class A {
public function sayHi(){
echo "HI\n";
}
}
$a = new A();
$s = serialize($a);
$b = unserialize($s);
$b->sayHi();
使用clone关键字可以复制对象,当对象被复制后,PHP对对象的所有属性执行一个浅复制(shallow copy),所有的引用属性仍然会是一个指向原来变量的引用。
<?php
class A {
public function sayHi(){
echo "HI\n";
}
}
$a = new A();
$b = clone $a;
$b->sayHi();
如果clone的目标对象带有变量,那clone后的新对象也带有同样的变量。
例如:
<?php
class A {
var $name,$age;
public function __construct($arg1='',$arg2=''){
$this->name = $arg1;
$this->age = $arg2;
}
}
$a = new A("Roshan",18);
$b = clone $a;
echo $b->name;