【辅导】Task12 使用类和对象 主要知识点(1)
PHP4中开始出现面向对象的影子。PHP5引入Zend Engine2后,才算真正引入面向对象机制。
本任务的辅导分成两阶段来进行,第一阶段辅导类的封装与继承,第二阶段辅导类的多态性。主要是与Java面向对象语法作比较,来熟悉PHP面向对象的语法和特点。
1、类的定义写在什么地方?
类的定义写在PHP代码文件任何地方都可以,像函数的定义一样。
但为了便于自动加载类文件,建议将每个类保存成单独的php文件,且以类名作为文件名,为便于管理,建议将类文件放在单独的文件夹中,如classes或libs等。
自动加载类函数__autoload
这里就要求,类文件以xxx.class.php命名,且放在classes文件夹中。
有同学指出,PHP7建议使用spl_autoload_register() 函数,它比__autoload更加灵活(可以定义多个自定义autoload函数),并且有更好的异常处理。有兴趣的同学看看这篇文章:
https://blog.csdn.net/wwx890208/article/details/82319676
如果只有一个自动加载函数,还是这个__autoload简单些。
2、PHP中如何定义类?
- class关键字前没有访问修饰符(类都是public的)
- 类名不区分大小写(同函数一样),但我们作为C系程序员,最好还是有区分大小写的好习惯,区分大小写的类名和函数便于阅读。
- PHP的类中可以有以下成员:字段(属性)、函数(方法),构造函数,析构函数等,同Java差不多。
- 类成员(包括属性和方法),默认是public的。
- 声明属性时,使用 var $x; 等同于public $x;
- 建议类字段定义为private或protected,需要公开时,定义getXXX或setXXX函数对外公开(我们在Java中就采用这种方式)
- 类内部使用类的字段时,要用$this伪变量,如:$this->x = $value;
- PHP成员运算符是->。(.运算符用作字符串连接了)
- 建议定义类时提供魔术方法__toString,明确类对象如何转换成字符串。
- PHP不支持函数重载(overloading),类继承时可以对父类函数重写(overwrite)
3、PHP中如何使用类
- 类对象实例化,使用new运算符,与Java一样。
- 使用类的成员:->运算符
小结一下:
- 在类的内部,引用类的成员,使用 $this->成员名
- 在类的内部,引用父类成员,使用 parent::成员名
- 在类的外部,引用对象成员,使用 $obj->成员名($obj是类对象变量)
4、构造函数
- 构造函数用来为对象做初始化工作。
- 构造函数名称必须是:__construct(这与Java不一样)
- 构造函数一般是public的。(实际上可以定义为private,但是这样一来就不能在类外部使用new来实例化对象了,这在单例模式下比较有用)。
- 构造函数只能有一个(即不能重载)。因为重载的目的是参数不同,而PHP是弱类型语言,所以我们可以使用默认参数来达到构造不同个数参数的目的。
BTW:实际上你可以不管函数的参数,你自己使用func_num_args()和func_get_args()来自己处理参数,但不推荐这么做。
5、析构函数
- 析构函数是在对象的所有引用都被删除或者当对象被显式销毁时执行。析构函数在脚本关闭时也会调用。
- 析构函数名称必须是:__destruct,没有参数,必须是public。
6、类的继承
- PHP中类继承的关键字是extends,与Java一样。
- 类继承会继承基类所有代码,包括基类所有私有成员,只是你没有访问权限而已。
- PHP同Java一样,只能实现单继承。
- 子类重写(overwrite)父类函数时,函数名和参数个数必须一致(因为PHP对类型不要求)
- 子类没有构造函数时,会自动从父类继承构造函数。如果子类定义了构造函数,不会隐式调用基类构造函数。(不像Java会调用基类默认构造函数)
- 所以,子类构造函数应当(不是必须)在第一行代码调用父类的构造函数。
- 子类调用父类构造函数:parent::__construct(参数列表);
- 要执行父类的析构函数,必须在子类的析构函数体中显式调用 parent::__destruct()。此外也和构造函数一样,子类如果自己没有定义析构函数则会继承父类的。
7、关于函数重载
前面我们多次提到,PHP中的函数和类中的方法不支持重载,一个函数只能定义一次。
但PHP手册说,PHP提供“重载”(overloading),参见:https://www.php.net/manual/zh/language.oop5.overloading.php
但这个重载与我们通常意义的重载不一样,它的意思是,当调用类对象中不存在的成员(字段或函数)或受访问限制的成员时,你采用自己的方式来处理它。它主要是用到魔术函数 __get(),__set(),__call()等。感兴趣的可以去了解下,有兴趣的话也可以就这个话题与我交流。
8、关于练习
大家可以在我提供的Point类基础上,练习创建Cricle类和Cylinder类,也可以自己去考虑下去创建Rectangle类(矩形)、Cube类(立方体)、Cone类(圆锥体)。