市面上,很多讲解PHP的书对面向对象的内容讲的很简单。而官方文档也不足之处,例如有些语法细节没有说清楚。还有,官方文档的内容感觉比较散,不能将所有面向对象的内容串联起来。所以,现做个学习笔记,将自己学习的PHP面向对象输出出来。
首先,面向对象的三个特点:封装、继承、多态。我将从这三个方面把PHP面向对象的内容都串联起来。接下来,将从封装的角度讲解PHP面向对象。
(一)所谓封装,最直观的理解就是将一些属性和方法定义到一个类里头。
那么如何定义一个类呢?
PHP的类有三种,普通类、抽象类、final类。
(1)普通类
普通类是说的最多的类,通常所说的类就是指普通类,可以被继承、可以实例化。
<?php
class foo{
//property
//method
}
?>
(2)抽象类所谓抽象类,就是只要含有抽象方法的类。抽象类可以被继承,但不能实例化。除此之外,抽象类与普通类就没有差别了。抽象方法就是没有方法体的方法。而且,抽象类中抽象方法的访问控制属性可以是private、protected、public,这与接口中的抽象方法不同,接口中抽象方法的访问控制属性只能是public。
<?php
abstract class foo{
//property
//method
abstract private function test1();
abstract protected function test2();
abstract public function test3();
//error
//abstract private function test1(){}
}
?>
(3)final类final类就是被final修饰的类,final类不可以被继承,可以实例化。除此之外,final类与普通类就没有差别了。
<?php
final class foo{
//property
//method
}
?>
(二)以上介绍了三种类的差别,接下来介绍在定义类时通用的语法。(1)类常量
定义类常量需要用const修饰,常量名无$,通常常量名采取大写的方式,且常量值必须是常数,比如数值、字符串,不能是变量、表达式等。类常量不能被static、public、protected、private修饰。
<?php
class foo{
const PI = 3.14;
//error
//const PI = 2 + 1.14;
//const public PI = 3.14;
}
?>
(2)属性定义属性和定义变量一样,遵循变量的命名规则。但是,如果要给属性赋值的话,值必须是常数。
<?php
class foo{
public $a = 1;
//error
//public $a = 1 + 1;
}
?>
(3)方法定义方法和定义函数是一样的。
<?php
class foo{
public function test(){
echo "test";
}
}
?>
(4)访问控制属性除了类常量,类成员(属性和方法)都有访问控制属性的,这是实现封装的重要方式。如果不显式地声明类成员的访问控制属性,则默认是public。访问控制属性有三种,public、protected、private。
public:可以正在所定义的类内部、子类内部、实例来访问。
protected:可以在所定义的类内部、子类内部访问。
private:只能在所定义的类内部访问。无法被继承。
(5)静态成员
使用static来修饰的类成员,分为静态属性和静态方法。静态属性和静态方法都是属于类本身的,类的实例不能访问静态成员(这个说法不太准确。实例可以访问静态方法,但是会报错,所以就认为不能访问更好一点),只有类可以访问静态成员。静态方法只能访问静态属性和静态方法。
(6)final方法
使用final修饰的方法,在类的继承中,不能被覆盖。
(三)类的定义说完了,接下来该说如何访问类中的成员
(1)类常量,静态成员
类常量和静态成员是属于类本身的,类存在它们就存在,所以它们是通过类来访问的,而不能通过类的实例来访问。
<?php
class foo{
const PI = 3.14;
public static $a = 1;
protected static $b = 2;
public static function test()
{
echo self::PI,"\n";
echo self::$a,"\n";
echo self::$b,"\n";
}
}
foo::test();
echo foo::PI,"\n";
echo foo::$a;
//error
//echo foo::$b;
?>
对于类常量和静态成员,都是使用双冒号的方式来访问。在类的内部,是使用self::的方式访问;在类的外部,使用类名::的方式访问。self,意思就是指类自己。在访问静态成员的时候,要注意其访问控制属性,如果被protected或private修饰了,就不能再类的外部访问。
(2)普通类成员
普通类成员是通过类的实例来访问的。
<?php
class foo{
public $a;
protected $b;
public function test()
{
$this->b = 2;
echo $this->a;
echo $this->b;
}
}
$obj = new foo;
$obj->a = 1;
$obj->test();
//error
//echo $obj->b;
?>
在类的内部,需要通过一个伪变量$this来访问普通类成员,以 $this->类成员 的方式来访问,$this就是对某个实例的引用;在类的外部,以 实例->类成员 的方式访问。在访问成员属性时,没有$。而且,要注意类成员的访问控制属性,只有public修饰的类成员被类的实例访问。
(四)实例化一个类
<?php
class foo{
//...
}
//通常都是这样
$obj1 = foo();
//在不需要初始化时,也可以这样
$obj2 = foo;
//这样也可以
$classname = foo;
$obj3 = $classname();
?>
创建一个实例时,如果定义了构造函数,就会自动调用构造函数完成初始化工作。<?php
class foo{
private $a;
function __construct($value)
{
$this->a = $value;
echo "init";
}
}
$obj = new foo(1);
?>
构造函数,__construct(),属于PHP面向对象语法中的魔术方法之一,只能这么命名。与之相对应的是析构函数,__destruct(),在销毁一个实例时会自动调用。注:如有不准确的地方,欢迎批评指正。