类和对象是语言用于构建程序的基本的component,PHP中的对象和类也不例外,我们可以将相关的操作通过类封装成不同的模块加以复用,即可构建出强大灵活的应用程序。
定义类及其方法
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?php
class Car { var $name = '汽车'; function getName() { return $this->name; } }
$car = new Car(); $car->name = '奥迪A6'; echo $car->getName(); ?>
|
public、protected、private属性的区别
在声明类属性时,默认都为public,外部可以访问。一般通过->
对象操作符来访问对象的属性或者方法,对于静态属性则使用::
双冒号进行访问。当在类成员方法内部调用的时候,可以使用$this
伪变量调用当前对象的属性。
受保护的属性(protected)与私有属性(private)不允许外部调用,在类的成员方法内部是可以调用的。
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?php class Car{ public $name="汽车"; protected $color="白色"; private $price="1000000"; public getColor(){ return $this->color; } } $car=new Car(); echo $car->name; echo $car->getColor(); echo $car->color;
|
方法、静态方法
方法就是在类中的function,很多时候我们分不清方法与函数有什么差别,在面向过程的程序设计中function叫做函数,在面向对象中function则被称之为方法。使用关键字static
修饰的,称之为静态方法,静态方法不需要实例化对象,可以通过类名直接调用,操作符为双冒号::
。
1 2 3 4 5 6 7 8
| <?php class Car { public static function getName() { return '汽车'; } } echo Car::getName(); ?>
|
构造函数、析构函数
在类中使用__construct()
定义一个构造函数,具有构造函数的类,会在每次对象创建的时候调用该函数,因此常用来在对象创建的时候进行一些初始化工作。
在子类中如果定义了__construct
则不会调用父类的__construct
,如果需要同时调用父类的构造函数,需要使用parent::__construct()
显式的调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?php class Car { function __construct() { print "父类构造函数被调用\n"; } } class Truck extends Car { function __construct() { print "子类构造函数被调用\n"; parent::__construct(); } } $car = new Truck(); ?>
|
析构函数使用__destruct()
进行定义,析构函数指的是当某个对象的所有引用被删除,或者对象被显式的销毁时会执行的函数。
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?php class Car { function __construct() { print "构造函数被调用 \n"; } function __destruct() { print "析构函数被调用 \n"; } } $car = new Car(); echo '使用后,准备销毁car对象 \n'; unset($car); ?>
|
static关键字
static用于定义类中的静态属性和方法。静态属性与方法可以在不实例化类的情况下调用,直接使用类名::
方法名的方式进行调用。静态属性不允许对象使用->
操作符调用。
静态方法中,$this
伪变量不允许使用。可以使用self,parent,static
在内部调用静态方法与属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <?php class Car { private static $speed = 10; public static function getSpeed() { return self::$speed; } public static function speedUp() { return self::$speed+=10; } } class BigCar extends Car { public static function start() { parent::speedUp(); } } $func = 'getSpeed'; BigCar::start(); echo BigCar::$func(); ?>
|
访问控制
被定义为public的类成员可以在任何地方被访问。被定义为protected的类成员则可以被其自身以及其子类和父类访问。被定义为private的类成员则只能被其定义所在的类访问。若方法采用var
定义,则被视为公有。
如果构造函数定义成了私有方法,则不允许直接实例化对象了,这时候一般通过静态方法进行实例化,在设计模式中会经常使用这样的方法来控制对象的创建,比如单例模式只允许有一个全局唯一的对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <?php class Car { private function __construct() { echo 'object create'; }
private static $_object = null; public static function getInstance() { if (empty(self::$_object)) { self::$_object = new Car(); } return self::$_object; } }
$car=Car::getInstance(); ?>
|
重载
PHP中的重载指的是动态的创建属性与方法,是通过魔术方法来实现的。属性的重载通过__set
,__get
,__isset
,__unset
来分别实现对不存在属性的赋值、读取、判断属性是否设置、销毁属性。
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
| <?php class Car { private $ary=array(); public function __set($key, $val){ $this->ary[$key] = $val; } public function __get($key){ if (isset($this->ary[$key])){ return $this->ary[$key]; } return null; } public function __isset($key){ if (isset($this->ary[$key])){ return true; } return false; } public function __unset($key){ unset($this->ary[$key]); } } $car = new Car(); $car->name = '汽车'; echo $car->name; ?>
|
方法的重载通过__call
来实现,当调用不存在的方法的时候,将会转为参数调用__call
方法,当调用不存在的静态方法时会使用__callStatic
重载。
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?php class Car { public $speed = 0; public function __call($name,$args){ if($name=='speedUp'){ $this->speed+=10; } } } $car=new Car(); $car->speedUp(); echo $car->speed; ?>
|
比较、复制、序列化
比较
当同一个类的两个实例的所有属性都相等
时,可以使用比较运算符==
进行判断,当需要判断两个变量是否为同一个对象的引用
时,可以使用全等运算符===
进行判断。
复制
在一些特殊情况下,可以通过关键字clone
来复制一个对象,这时__clone
方法会被调用,通过这个魔术方法来设置属性的值。
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?php class Car { public $name='car'; public function __clone(){ $obj=new Car(); $obj->name=$this->name; } } $a=new Car(); $a->name='new car'; $b=clone $a; var_dump($b); ?>
|
序列化
可以通过serialize
方法将对象序列化为字符串,用于存储或者传递数据
,然后在需要的时候通过unserialize
将字符串反序列化成对象进行使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <?php class Car { public $name = 'car'; public function __clone() { $obj = new Car(); $obj->name = $this->name; } } $a = new Car(); $str = serialize($a); echo $str.'<br>'; $c = unserialize($str); var_dump($c); ?>
|
输出
1 2 3 4 5
| O:3:"Car":1:{s:4:"name";s:3:"car";} object(Car)#3 (1) { ["name"]=> string(3) "car" }
|
感觉这个序列化貌似并不常用,即使序列化了也还是只有PHP的反序列化方法可以识别并反序列化。