PHP面向对象
面向过程的编程的基本构成是“过程“,过程的实现方式是”函数“,通过不同函数来实现不同的功能,并按照程序的执行顺序调用相应的函数,组成一个完成整的可以运行的程序,通过把不同功能在不同的函数中实现或者给函数传递不同的参数来实现不同的功能,这是面向过程中模块化设计的原理。但是当设计一些大型的应用时,就会出现代码极难维护、要为相似的功能设计不同的函数且代码量极大等问题。
一、什么是面向对象
- OOP(object-Orientied programming):将现实世界各类物质的特征和行为用编程语言进行抽象表达,具备比面向过程更加高级的特性。
1.什么是类
- class: 类是”一类事物的统称“,比如”门”就是一类东西,“防盗门”、“汽车门“也是一类东西。人、男人、女人等,同类由相同的特征和行为。如门的特性:材质、高、款、样式、颜色……,门的行为:打开、关闭、上锁……
2.什么是实例
- instance: 实例是明确告知哪一类东西的哪一个,比如”小明家的入户门“
3.什么是对象
- 在面向对象的程序设计中,“一切皆对象”。一个类是一个对象,一个实例是一个对象,一个变量也是一个对象,甚至一个数据类型也可以视为一个对象。
4.对象有什么特性
- 对象有方法,比如门可以”开“、可以”关“、可以”锁“,这些属于方法,也成为对象的行为。
- 对象有属性,如门有材质、高、款、样式、颜色等,这些属于属性,也可称为特性。
属性类似于面向过程中的变量,方法类似与函数,它们之间唯一的区别在于函数不存在公有私有一说,而方法却有访问修饰符(public,private,protected等),这种修饰符直接决定了该方法能不能被别的子对象使用。
二、封装、继承、多态、魔术方法
1.封装
-
public:公有,默认情况下,所有属性和方法在没有明确设置访问修饰符时都是public
- 该类型的属性在序列化时格式为正常成员名
-
private:私有,在类的定义中可以使用,而在实例和子类中都无法使用
- 对于私有属性,可以设置一个公有方法,对类的私有属性进行修改或取消
- 该类型的属性在序列化时格式为
%00类名%00成员名
-
protected:受类的保护,实例中不能直接使用,但是在子类中可以使用
- 该类型的属性在序列化时格式为
%00*%00成员名
- 该类型的属性在序列化时格式为
2.继承
- 子类可以继承父类的属性和方法(非私有)
- 子类无法直接使用父类的私有属性和私有方法
- 父类中拥有的方法,在子类中可以进行覆盖,也称重写
- 子类的实例一样无法使用父类的受保护方法,需要在子类定义中调用
- 子类也可以在自己类扩展或创建新的方法和属性
- 关键字final,如果一个类被final修饰,则不能继承
3.多态
- 针对弱类型的编程语言,多态的描述并不是特别准确,多态在强类型编程语言(java,C#,C++),多态非常重要。
- 多态指一个对象可以扮演多个角色
抽象类;只有类的方法中有一个方法使用abstract关键字定义,则该类就是抽象类,该方法是抽象方法,抽象类不能实例化,只能被继承,抽象方法不能有实现代码。接口就是极端的抽象,只能方法的定义,不能有方法的实现,通常用于定义一些规则。
4.魔术方法
魔术方法 | 触发时机 |
---|---|
__construct() | 类的构造函数,在类实例化对象时自动调用构造函数 |
__destruct() | 类的析构函数,在对象销毁之前自动调用析构函数 |
__sleep() | 在对象被序列化(使用 serialize() 函数)之前自动调用,可以在此方法中指定需要被序列化的属性,返回一个包含对象中所有应被序列化的变量名称的数组 |
__wakeup() | 在对象被反序列化(使用 unserialize() 函数)之前自动调用,可以在此方法中重新初始化对象状态。 |
__set(\$property, $value) | 当给一个对象的不存在或不可访问(private修饰)的属性赋值时自动调用,传递属性名和属性值作为参数。 |
__get($property) | 当访问一个对象的不存在或不可访问的属性时自动调用,传递属性名作为参数。 |
__isset($property) | 当对一个对象的不存在或不可访问的属性使用 isset() 或 empty() 函数时自动调用,传递属性名作为参数。 |
__unset($property) | 当对一个对象的不存在或不可访问的属性使用 unset() 函数时自动调用,传递属性名作为参数。 |
__call(\$method, $arguments) | 调用不存在或不可见的成员方法时,PHP会先调用__call()方法来存储方法名及其参数 |
__callStatic(\$method, $arguments) | 当调用一个静态方法中不存在的方法时自动调用,传递方法名和参数数组作为参数。 |
__toString() | 当使用echo或print输出对象将对象转化为字符串形式时,会调用__toString()方法 |
__invoke() | 当将一个对象作为函数进行调用时自动调用。 |
__clone() | 当使用 clone 关键字复制一个对象时自动调用。 |
__set_state($array) | 在使用 var_export() 导出类时自动调用,用于返回一个包含类的静态成员的数组。 |
__debugInfo() | 在使用 var_dump() 打印对象时自动调用,用于自定义对象的调试信息。 |
三、示例
<?php
// 面向对象编程
// 定义类:People
class People {
var $name = '张三'; // 不在称为变量,而是叫类属性,定义类时可以设置初始值
public $age = 0; // 使用了访问修饰符,不再需要var
var $addr = '';
private $nation = '汉族'; // 私有属性
// 定义People类所具备的方法,默认情况下,方法的定义与函数完全一致
public function talk(){
// 在类的定义中,$this指类的具体实例
echo "$this->name 正在说话";
}
// 可以用公有方法调用该私有方法
private function work(){
echo "$this->name 在工作";
}
protected function eat($type){
echo "$this->name 正在吃 $type";
}
function whatNation(){
echo "$this->name 是 $this->nation";
}
// 以下两个方法是封装这个特性最经典的演示,公有方法操作私有属性
function setNation($nation){
$this->nation = $nation;
}
function getNation(){
return $this->nation;
}
}
// 实例化类People进行属性和方法的调用
$p1 = new People();
$p1 -> name = "李四";
$p1 -> age = 30;
$p1 -> addr = "北京";
echo $p1 -> name;
$p1 -> talk();
$p = new People();
$p->nation = "回族"; // 实例无法使用类的私有属性
$p->whatNation(); // 显示为“张三是汉族”
$p->setNation('回族');
echo $p->getNation();
$p->eat('米饭'); // 受保护方法无法使用
// 创建People的子类Man,子类可以继承父类的属性和方法(非私有)
class Man extens People {
// Man这个类可以什么都不做,People的所有非私有属性和方法都可使用
// 父类中拥有的方法,在子类中可以进行覆盖,也称重写
function work(){
echo "this->name 正在工作 ";
}
public function talk(){
echo "$this->name 正在说话";
// 在子类定义中调用父类的protected方法
// $this->eat();
parent::eat(); //通常使用这种做法调用
}
}
$m = new Man();
$m->talk();
$m->eat('米饭'); // 子类的实例一样无法使用父类的受保护方法
$m->talk(); // 此时可以调用eat方法
echo $m->nation; // 子类无法直接使用父类的私有属性
// 但是子类可以直接定义一个父类拥有的相同属性
$m->nation = "藏族";
$m->whatNation();
?>