思想图解:
就是把个个方法对应到它的主题,买家的方法就对应到买家那里,卖家的方法就放到卖家那里,凡是做任何一件事都有一个操作的主体,虽然更复杂,但是更符合人类的思想
关键字说明
- 类: class,是定义面向对象主体的最外层结构,用来包裹主体的数据和功能(函数)。类是一类具有共性事务的代表,代表的是事务的共性。
- 对象: object,是某类事务的具体代表,也是实际数据和功能操作的具体单元,也被称之为实例(instance)
- 实例化: new,从一个抽象的概念得到一个符合抽象概念的具体实例的过程
- 类成员:member,指类class结构中的所有内容,类成员里有三种
- 方法: method,本质是在类class结构中创建的函数,也称之为成员方法或者成员函数
- 属性: property,本质是在类class结构中创建的变量,也称之为成员变量
- 类常量: const,本质是在类class结构中创建的常量
类的定义
类成员
类成员:指直接定义在类结构内部的一级成员,即直接依赖f的成员
-
类成员分类
- 成员变量(属性)︰给对象存储数据的变量。成员函数((方法)︰给对象调用解决问题的函数
- 类常量:属于类内部的常量,使用const关键字定义
-
属性和方法需要使用访问修饰限定符修饰,姑且使用public修饰
<?php
class 类名{
# 类常量
const 常量名 = 值;
# 属性
public $属性名 [ = 值]; # 可以赋值也可以只声明
# 方法
[public] function 方法名([形参列表]){
方法体
}
}
- 成员访问:属性和方法都属于对象访问,类常量属于类访问(后续再讲)
- 对象访问属性和方法,使用
->
- 对象访问属性和方法,使用
<?php
# 实例化
$object = new 类名();
# 属性访问
# 此时不带属性本身的$符号(前面保存对象的变量带$符号,object->属性名是整体)
$object -> 属性名;
# 方法访问
$object -> 方法名([实参列表]);
步骤
1、声明类结构工
2、明确类产生的对象是否需要有数据的存储:确定属性
3、明确类产生的对象是否需要函数实现功能:确定方法
4、明确类是否需要定义常量:确定类常量
5、对象实例化
6、类成员访问(属性和方法)
实例:
属性的操作:
增,删,改,查
小结
1、PHP类结构中有且仅有三种成员:属性、方法和类常量,其他直接属于类的内容都会报错
2、类声明需要根据业务来确定类成员的存在和数量
3、类中属性和方法的访问方式都是通过对象来调用: $对象->属性名/方法名();
注意属性名不带$符号
4、类中定义属性不能直接属性名,需要使用符号public修饰(访问修饰限定符中的一种)
访问修饰限定符
分类:
- public:公有,类内和类外都可以访问
- protected:受保护,只允许在相关类内部访问(前期的学习就当作私有)
- private:私有,只允许在定义类内部访问
- 属性必须有访问修饰限定符,方法可以没有访问修饰限定符(默认public)
类内部对象
概念
内部对象:$this,方法内部内置的一个对象,会自动指向来调用方法的对象
- $this存在于方法内部(仅限内部使用),所以相当于在类的结构内部
- 可以访问任意访问修饰限定符修饰的成员
- 私有成员都是通过公有方法来实现访问(公有方法可以在类外部访问)
- 类内部对类成员的访问也需要通过对象才能访问,所以必须通过$this内部对象访问类成员
步骤
-
声明类结构
-
明确私有成员(不限定成员的访问修饰限定符)
-
私有成员需要在某种情况下被访问:增加方法,在方法里使用$this访问
例如:在类内部访问属性,可以让本来不能访问类的私有的属性和方法的对象成功访问
class Saler{
# 属性
public $count = 100;
protected $discount = 0.8;
private $money = 100;
public function getAll(){
var_dump($this);
echo $this->count,$this->discount,$this->money; #正确输出
}
}
$s = new Saler();
$s->getAll();
$this、class和new之间的关系原理
-
class是定义类结构,属于非执行段代码,因此会被加载到代码段(编译阶段)
-
new是实例化对象,先判定类在内存(代码段)是否存在
- 类不存在,报错;
- 类存在,将类内部的属性部分复制一份,然后在内存(堆区)开辟一块内存空间,将属性放到里面,同时内部有一个指针指向类的内存空间(代码段)
- 对象访问属性即访问的是对象空间里存储的部分
- 对象访问方法是对象通过内部指针找到类空间中的方法,然后在内存(栈区)开辟运行
-
$this是系统在方法内置的对象通用名字
- 对象在调用方法的时候,系统会自动找到对象所保存的内存地址(堆区),然后把地址赋值给$this
-
方法内部的$this就代表调用当前$this所在方法的外部对象
- $this的本质是函数内部的一个局部变量,只是系统自动对其进行赋值,而且一定是调用方法的对象本身
-
面向对象编程代码运行内存关系
构造方法
概念
构造方法:__construct()
,是一种类结构特有的特殊方法,该方法由系统规定好,开发人员在定义的时候只需要抄一遍,有了构造方法的类在实例化对象之后,对象就会自动调用。
- 构造方法是一种魔术方法:魔术方法是会自动被触发,不需要手动调用的方法
- 构造方法的目标是为了实现对象的初始化
- 对象实例化之后会自动调用
- 构造方法通常是为了实现对象所需资源的初始化(属性、资源)
- 构造方法虽然为魔术方法,但本质依然是一个方法
- 受访问修饰限定符控制(对象的产生位置会发生改变)
- 对象可以选择调用(一般不会)
- 构造方法可以设定形参,形参对应的实参是在实例化对象的时候传入:new 类名(实参传递给形参)
步骤
-
确定类中需要有数据实现初始化,而且是灵活处理,每个对象都不一样的:使用构造方法
-
确定初始化的数据需要外部传入:使用构造方法设定形参
-
在构造方法内部利用内部对象实现初始化需求
- 属性初始化
- 资源初始化
- 其他内置方法调用
-
实例化对象时必须传入构造方法所需数据
示例
1、构造方法实现:在类中增加一个方法__construct()即可
2、构造方法也是一个方法,不普通的地方在于,类实例化得到的对象会马上自动调用
3、一旦构造方法拥有了形参,那么对象在调用该方法的时候就需要传入对应的实参,而构造方法又是自动调用的,所以需要在实例化对象的时候使用new 类名(构造方法对应的实参列表)来实现
4、构造方法不管再怎么特殊,也是用户定义的方法,言外之意除了在实例化对象时对象会自动调用之外,我们也可以手动调用构造方法(但是一般没有价值,因为对象实例化时会自动调用)
class Saler{
# 属性
public $count;
private $money;
# 构造方法:初始化属性
public function __construct($count,$money){
$this->count = $count;
$this->money = $money;
}
}
# 实例化
$s = new Saler(100,100); # 系统在new Saler(100,100)好之后,会自动调用一次
$s->__construct(1000,1000); # 允许手动调用
小结
1、构造方法__construct()是一种系统内置的方法,该方法的特性是会在对象实例化之后,对象立即自动调用
2、构造方法的目的就是为了初始化资源,包含对象属性和其他资源
3、一旦构造方法定义好之后,且构造方法自带参数,那么就只能使用new 类名(参数列表)
方式才能正确实例化
4、构造方法可以当做普通方法由对象调用(不建议)
析构方法
概念
析构方法:__destruct()
,也是一种类结构中魔术方法,与构造方法一样,也是系统规定好,只需要开发人员抄一遍即可,对象在被销毁时会自动调用
- 析构方法是用来对象销毁时主动释放资源的
- 对象销毁的方式:
- 对象无变量指向(变量指向其他数据比如重新赋值)
- 对象被主动销毁(unset销毁对象变量)
- 脚本执行结束(自动释放资源)
- PHP脚本执行结束会释放所有资源,所以一般较少使用析构方法
步骤
1、定义类结构
2、确定需要在对象销毁时释放资源
3、使用析构方法释放资源
示例
1、析构方法实现:类中增加一个__destruct()方法
class Saler{
# 析构方法
public function __destruct(){
echo __FUNCTION__;
}
}
2、析构方法调用:析构方法是在对象被销毁时自动,对象的“垂死挣扎”
# 实例化对象
$s = new Saler();
# 对象变量指向其他数据
$s = 1;
# 主动销毁对象变量
unset($s);
# 脚本执行结束自动释放
3、析构方法也是普通方法,可以由对象直接调用
# 接析构方法实现代码
$s = new Saler();
$s->__destruct(); # 调用了对象是不会被销毁的
小结
1、析构方法是一种对象销毁时自动调用的方法
2、析构方法是用来对象销毁自身所占用的资源
3、PHP中脚本执行结束,系统会自动回收所有资源,因此一般PHP中很少使用析构方法
对象传值
概念
对象传值:将保存对象的变量赋值给另外一个变量
- 在PHP中,对象的传值是引用传递的:即一个对象变量赋值给另外一个变量,两个变量指向同一个对象的内存地址,即只有一个对象。
步骤
1、定义类结构
2、实例化产生对象,保存在变量中
3、将保存对象的变量赋值给另外一个变量
示例
-
对象传值就是保存对象的变量赋值给另外一个变量
-
对象传值是引用传递,不管对象赋值给多少个变量,内存中只有一个对象
class Saler{}
$s1 = new Saler();
$s2 = $s1;
var_dump($s1,$s2); # 同一个对象
$s1->name = 'Saler'; # 更改一个变量所保存对象的属性
echo $s2->name; # 输出Saler
小结
对象传值方式是引用传值,不论对象如何被赋值给其他变量,始终只有一个对象
范围解析操作符(类常量访问)
概念
范围解析操作符:由两个冒号组成“::”,是专门用于类实现类成员操作的(区别于对象对类成员操作),可以实现类直接访问类成员
- 范围解析操作符是用于给类(类名)访问类成员使用的
类名::类成员
- 范围解析操作符也可以被对象用来当做类使用(不建议使用)
$对象名::类成员
- 类常量只能被类访问
步骤
1、定义类结构
2、确定成员需要由类进行管理:类常量
3、在需要访问类常量的时候使用范围解析操作符访问
示例
1、类常量的普通访问尝试:尝试使用对象进行访问
class Saler{
# 类常量
const PI = 3.14;
}
$s1 = new Saler();
echo $s1->PI; # 错误,$s1->PI最终转换的访问方式为:$PI,这个在类中并不存在
2、以上案例可以看出,对象无法访问类常量,那是因为类常量的定义本身就是用来给类访问的,对象是用来访问属性和方法的,类常量的访问方式为:类名::常量名
,而且类的访问不需要依靠对象,就算没有实例化对象也可以访问
# 类+范围解析操作符访问类常量
echo Saler::PI; # 输出3.14
3、对象本身也依赖于类,因此也可以使用对象对类控制成员进行访问,需要使用范围解析操作符
$s = new Saler();
echo $s::PI; # 输出3.14
注意:以上方式能访问,但是不建议使用(以上方式也能看出,成员谁来访问,关键看用什么符号:①使用范围解析操作符::
就是类访问;②使用对象操作符号->
就是对象访问)
4、分析:类常量是固定的,而对象的属性是不同对象而不同的,成员方法简单的理解也是为属性本身进行加工的。因此有一些东西是专属于类的,而有部分内容是专门为对象提供的,所以就会有不同的成员拥有不同的访问方式
小结
1、类访问成员的方式是使用范围解析操作符“::”访问,由类名直接访问:类名::类常量
2、类本身是通过对同类对象的抽象而形成,所以属性和方法本身都是由对象来访问
3、类也需要有一些自身的数据和操作,这些就由类来进行访问
静态成员
概念
静态成员:使用static关键字
修饰的类成员,表示该成员属于类访问(专用于类)
- PHP静态成员有两种
- 静态属性
- 静态方法
- 静态成员是明确用来给类访问的,而不是对象
- 静态成员只是多了一个static关键字修饰,本身也可以被对象访问
- 静态成员同样可以使用不同访问修饰限定符限定,效果一致
步骤
1、定义类结构
2、确定有些成员(属性、方法)不需要对象访问,直接通过类访问
3、使用static关键字修饰
4、静态成员应该让类进行访问
示例
1、静态属性:在类中定义属性的时候使用static关键字修饰,访问的时候只能使用类+范围解析操作符+静态属性访问
,对象不能访问静态属性
class Saler{
# 属性
public $money = 0;
public static $count = 0; # 静态属性
}
# 静态成员可以直接使用类访问,而不需要先实例化对象
echo Saler::$count;
$s = new Saler;
echo $s->count; # 错误访问,对象不能访问静态属性
2、静态方法:在类中定义方法的时候使用static关键字修饰,访问的时候使用类+范围解析操作符+静态方法名字()
访问
class Saler{
# 方法
public static function showClass(){
echo __CLASS__;
}
}
# 类直接访问
Saler::showClass();
3、在类的内部也可以访问静态成员,同样是使用类名+范围解析操作符+静态属性/静态方法()
class Saler{
# 属性
private static $count = 0; # 私有,不允许外部直接访问
# 方法
public static function showClass(){
echo Saler::$count;
}
}
# 类直接访问
Saler::showClass();
4、静态方法本质也是类中定义的方法,因此也可以使用对象进行访问,但是不建议
# 对象访问静态方法
$s = new Saler();
$s->showClass(); # 输出0
5、同理,方法也是在类内部,在编译时就存在,因此可以通过类来进行访问,使用范围解析操作符,但是非常不建议(会报错:因为类只允许访问静态成员和类常量)
class Saler{
public function testStatic(){
echo __FUNCTION__;
}
}
# 类访问普通成员方法
Saler::testStatic(); # 输出testStatic,但是报错,当前访问的不是静态方法
6、静态方法本质是给类访问,所以不允许在静态方法内部使用$this对象
class Saler{
public static function testStaticThis(){
var_dump($this); # 致命错误:$this放到了不该放的位置
}
}
小结
1、为了保障类能直接访问数据和操作数据,可以在属性和方法前增加static关键字变成静态属性和静态方法
2、类通过类名+范围解析操作符+静态成员的方式进行访问
3、静态成员也受访问修饰限定符的限定,访问权限与普通属性和方法的限制一样
4、对象可以无条件访问静态方法,而类只能访问不带$this的普通方法(不建议)
5、静态成员是给类访问的,非静态成员是给对象访问的
- 静态属性和方法(静态和非静态)都是保存在类结构中(代码段)
- 普通属性保存在对象生成的对象空间里(堆)
6、静态成员的访问效率比非静态成员高,因此有种说法是能用静态的时候就不用非静态(对象的特点是多元化,而静态的特点是单一化)
self关键字
概念
self关键字:在类的内部(方法里面)使用,代替类名的写法
-
self如同$this代表内部对象一样,能够在方法内部代替当前类名
-
能够保障用户方便修改类名字
-
self关键字是代替类名,所以需要配合范围解析操作符
::
步骤
1、定义类结构
2、方法内部需要使用类名来进行成员访问(类常量、静态成员)
3、使用self关键字代替类名
示例
1、self是用来代替类名的,与范围解析操作符::
一起使用的
class Saler{
# 静态属性
private static $count = 0; # 私有,不允许外部直接访问
# 静态方法
public static function showClass(){
echo Saler::$count;
echo self::$count; # 代替类名
}
}
2、self也可以在类的内部方便实例化对象:比如构造方法被私有化之后,就没有办法在类外部实例化对象,此时可以在类内部进行对象实例化
class Saler{
# 属性
private static $count = 0; # 私有,不允许外部直接访问
private function __construct(){} # 私有,不允许外部实例化(因为对象不能外部调用)
# 方法
public static function getInstance(){
return new Saler(); # 使用类名实例化
return new self(); # 使用self关键字实例化
}
}
$s = Saler::getInstance();
小结
1、self是一种在类内部用来代替类名的关键字
2、self可以用来在类内部访问静态成员
3、self也可以在类内部用来实例化对象
4、帮助类名修改时,不用修改任何类的内部结构