文章目录
一、类与对象
1.1 成员属性
定义:
类的变量
属性的声明有:private
>protected
>public
数据类型:1、基本数据类型(整型int
、浮点型float
、字符串string
、布尔bool
);2、复合数据类型(数组array
、对象object
);3、特殊数据类型(null
、资源
)
二、构造函数
2.1 语法
// 访问修饰符:private、protected、public 默认 public
// 构造函数是创建对象时,由系统自动调用
访问修饰符 function __construct(形参列表){
// 完成对成员属性的初始化
}
2.2 this说明
系统会给每个对象分配
this
,代表当前对象
this
只能在类内部方法中使用,不能在类定的的外部使用。
三、析构函数
3.1 语法
public function __destruct(){
// 释放该对象的资源
}
定义:在到某个对象的
所有引用都被删除
或者当对象被显式销毁
时执行,说白了就是对象调用结束前
场景:析构函数是在对象被销毁前, 给程序员一个机会,去释放该对象分配的相关资源的, 比如数据库链接, 比如你打开的文件,比如绘图的句柄
3.2 垃圾回收机制
1、php中,一个对象没有任何引用指向它时,就会成为一个垃圾对象,php将启用垃圾回收器将对象销毁
2、当程序退出前,php也会启用垃圾回收器,销毁对象
四、魔术方法
4.1 说明
1、程序员不能主动的调用魔术方法, 当满足某个条件时,系统会自动的调用魔术方法
2、魔术方法是系统给我们提供的
3、魔术方法都是以__
开头的,因此我们自定以函数时,就不要使用__
开头
4.2 方法的访问修饰符
public
: 在任何地方被访问
protected
: 可以被其自身
以及其子类
和父类
访问
private
: 只能在该类
里面访问
4.3 魔术方法介绍
① __get 和 __set
1、读取不可访问属性的值时,
__get()
会被调用 // 都是在类的内部定义,外部调用
2、在给不可访问属性赋值时,__set()
会被调用
3、不可访问的属性就是指这样的情况(1. 属性不存在
、2. 属性是protected
或private
)
/**
* __get()
* @param $get_name [string] [你要获取的属性名,这里是protected、private才被调用]
*/
public function __get($get_name){
# property_exists():检查对象或类是否具有该属性
if(property_exists($this, $get_name)){
return $this->$get_name;//返回该类的对应属性值
} else {
return '没有这个属性';
}
}
/**
* __set()
* @param $set_name [string] [你要设置的属性名,这里是protected、private才被调用]
* @param $set_val [string] [你要设置的属性值,这里是protected、private才被调用]
*/
public function __set($set_name, $set_val){
# property_exists():检查对象或类是否具有该属性
if(property_exists($this, $set_name)){
return $this->$set_name = $set_val;//返回该类的对应属性值
} else {
return '没有这个属性';
}
}
② __isset 和 __unset
1、当对不可访问属性调用
isset()
或empty()
时,__isset()
会被调用.变量存在则传回true,否则传回false
2、当对不可访问属性调用unset()
时,__unset()
会被调用
3、不可访问的属性就是指这样的情况(1. 属性不存在
、2. 属性是protected
或private
)
③ __toString
当我们把一个对象当做字符串输出时,就会自动的调用
__toString
④ __clone
当我们去克隆一个对象时,
__clone
方法就会被自动的调用
⑤ __call
1、在对象中调用一个不可访问
方法
时,__call()
会被调用
2、注意这里的__call(
string$method
, array$args)
里面必须有2个参数第一个是要调用类里面的方法名,第二个是实例化该类传进来的参数
3、不可访问的属性就是指这样的情况(1. 属性不存在
、2. 属性是protected
或private
)
⑥ __callStatic
1、当我们调用一个不可以访问的静态方法时,
__callStatic
魔术方法就会被触发
2、不可访问的方法就是指这样的情况(1. 方法不存在
、2. 方法是protected
或private
)
五、类的自动加载
5.1 自动加载:__autoload
创建一个类名和类文件的映射数组
/**
* [old]: 以前是分别引入 require() 文件
* [now]: 现在创建一个类名和类文件的映射数组
*/
$map = array(
'Cat' => './Cat.php',
'Dog' => './Dog.php',
'Tiger' => './Tiger.php',
'Sheep' => './Sheep.php',
// ... => ...
);
/**
* 功能:当我们使用一个没有定义的类名时,该函数就会被调用
* @param $class_name [string] [被调用的类名]
*/
public function __autoload($class_name) // 注意:这里使用的是php自带的__autoload()方法
{
# 动态引入类 $map 就是上面定义的数组,用global引入方法内使用
global $map;
require $map[$class_name];
}
5.2 回调函数:spl_autoload_register
我们可以使用
spl_autoload_register
(回调函数) 来注册自己的自动加载函数,注意前面没有__
/**
* [old]: 以前是分别引入 require() 文件
* [now]: 现在创建一个类名和类文件的映射数组
*/
$map = array(
'Cat' => './Cat.php',
'Dog' => './Dog.php',
'Tiger' => './Tiger.php',
'Sheep' => './Sheep.php',
// ... => ...
);
/**
* 功能:当我们使用一个没有定义的类名时,该函数就会被调用
* @param $class_name [string] [被调用的类名]
*/
public function my__autoload($class_name) // 注意:这里使用的自定义的 my__autoload()方法
{
# 动态引入类 $map 就是上面定义的数组,用global引入方法内使用
global $map;
require $map[$class_name];
}
// 使用spl_autoload_register()注册[自定义]的加载函数
spl_autoload_register('my__autoload');
六、静态属性
概念:静态属性是该类的所有对象
共享的变量
,任何一个该类的对象去访问它时,取到的都是相同的值;同样修改它时,修改的也是同一个变量。
定义:访问修饰符 static 静态属性名
6.1 如何访问静态属性
1、在类的外部如何访问静态属性 ,必须为
public
类名::$静态属性名
2、在类的内部访问静态属性,可以是
public
、protected
、private
第一种 ==> 类名::$静态属性名;
第二种 ==> self::$静态属性名; //常用第二种,灵活
注意:
self
是类的范畴(指向类),$this
是对象实例(指向对象实例)
七、静态方法
概念: 静态方法通常是用来操作
静态属性
的,静态方法又称类方法
定义:访问修饰符,可以是public
、protected
、private
访问修饰符 static function 方法名(形参列表){
//函数体
}
7.1 如何访问静态方法
1、在类的外部如何访问静态方法 ,必须为
public
类名::静态方法名(参数)
2、在类的内部访问静态属性,可以是
public
、protected
、private
第一种 ==> 类名::静态方法名(参数); // 常用第一种
第二种 ==> self::静态方法名(参数);
第三种 ==> $this->静态方法名(参数);
7.2 注意事项
注意:
1、 静态方法中不能访问非静态属性
;普通的成员方法,可以访问静态属性
和非静态属性
2、如果我们的静态方法是protected
或private
则也不能在类的外部使用
7.3 静态方法和静态属性的最佳实践
单例模式
八、oop编程的三大特征 – -- 封装
抽象
定义: (就是将一类事物的共同特征
[属性, 行为(成员方法)]
提取出来,形成一个模板(类), 这种研究问题的方式就是抽象
8.1 封装
定义:是将数据
(成员属性)
和操作(成员方法)
封装在一起,把数据保护起来的目的,如果需要操作数据,需要通过被授权的方法(通过public
的成员方法)才可以实现
8.2 封装是如何实现
在php的面向对象中,是通过
访问控制符
来实现封装的, 具体的说就是通过public
,protected
和private
来实现
九、oop编程的三大特征-- – 继承
概念:
1、把多个类共有的属性和方法
提出来,做成一个A类(父类,基类)
2、让B、C类继承A类(extends
);B、C称为子类,扩展类
3、在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法
定义:
class 类名 extends 父类名{
//属性,方法等等.
}
9.1 继承细节
1、父类的
private
修饰的属性和方法,在子类中不能使用
2、承不能简单的理解成子类定义时,会把父类的属性声明,方法定义拷贝一份,而是建立了继承查找
的的关系
3、子类最多只能继承一个
父类(指直接继承)
4、在创建某个子类对象时,默认情况下会自动调用其父类的构造函数
5、如果在子类中需要访问其父类的方法(构造方法/成员方法
方法的访问修饰符是public/protected
),可以使用父类::方法名(或者 parent::方法名 )
来完成
6、如果子类(扩展类)中的方法和父类(基类)方法相同,我们称为方法重写
9.2 重载
9.2.1 方法重载
所谓
方法重载
,就是函数或者方法有相同的名称,但是参数列表不相同的情形,这样的同名不同参数的函数或者方法之间,互相称之为重载函数或者重载方法。例如:JAVA,因为JAVA没有参数默认值,用方法重载
public class OverloadDemo {
//1. test()方法第一次重载,没有参数
void test() {
System.out.println("No parameters");
}
//2. test()方法第二次重载,一个整型参数
void test(int a) {
System.out.println("a: " + a);
}
//3. test()方法第三次重载,两个整型参数
void test(int a, int b) {
System.out.println("a and b: " + a + " " + b);
}
//4. test()方法第四次重载,一个双精度型参数
double test(double a) {
System.out.println("double a: " + a);
return a * a;//返回a*a的值
}
}
在php中,是通过
魔术方法
__call()来实现方法重载。PHP可以参数默认值,所以正常不需要方法重载操作
方法重载优势,开发调用效率相对高一些
/**
* [old]以前方法重载,通过参数个数和类型不同来区分
*/
public function index($foo1, $foo2){
// todo...
}
public function index($foo1, $foo2, $foo3){
// todo...
}
/**
* [now]现在重载,通过参数个数和类型不同来区分
*/
class A{
public function index($foo1, $foo2){
// todo...
}
public function index2($foo1, $foo2, $foo3){
// todo...
}
// 使用模式方法实现 用魔术方法 __call 访问一个不存在或无权限方法时调用
public function __call($method, $args)
{
// 实现处理方法,使用__call()判断参数个数
if(count($args) == 2){
$this->index($args[0], $args[1]); // 调用index()
}else if(count($args) == 3){
$this->index2($args[0], $args[1], $args[2]); // 调用index2()
}
}
}
$a = new A();
$a->null_fun($num1, $num2); // 调用一个A类不存在的方法null_fun,会触发A类中的__call方法。
9.2.2 属性重载
/**
* 编写一个 public 的 __set()就可以阻止属性重载
*/
class B{
public $color; // 存在属性
private $pro_arr = array(); // 存储不存在,外部传入的属性
public function __set($pro_name, $pro_val){
if(!property_exists($this, $pro_name)){
$this->pro_arr[$pro_name] = $pro_val; // 把调用B类时传入的值赋予传入属性
}
}
public function __get($pro_name)
{
if(isset($this->pro_arr[$pro_name])){ // 查询调用B类时传入的属性有无对应的属性
$this->pro_arr[$pro_name];
}else{
echo '属性不存在';
}
}
/**
* 这里只是为了当外部传入B类的属性后,打印出来看B类的属性
*/
public function showAllPro()
{
echo '<br>动态增加的属性有 ==> ';
foreach ($this->pro_arr as $k => $v) {
echo '<br>属性名:' . $k;
echo '<br>属性值:' . $v;
}
}
}
$b = new B();
$b->name = '不存在名字'; // B类中不存在该属性
$b->address = '不存在地址'; // B类中不存在该属性
$b->color = '存在颜色红色';// B类中存在该属性
// 打印B类看里面属性做对比
echo '<pre>';
var_dump($b);
echo '<hr>';
$b->showAllPro();
输出结果如下
object(B)#1 (2) {
["color"]=>
string(18) "存在颜色红色"
["pro_arr":"B":private]=>
array(2) {
["name"]=>
string(15) "不存在名字"
["address"]=>
string(15) "不存在地址"
}
}
动态增加的属性有 ==>
属性名:name
属性值:不存在名字
属性名:address
属性值:不存在地址
关于重载,PHP中,有三种方式处理
1、使用默认机制,不去管理
2、组织开发者使用重载,很有必要
3、可以自己管理属性重载
十、oop编程的三大特征-- – 多态
概念: 指的是对象在不同的情况下的多种状态, 根据面向对象时运行的上下文环境来决定
/***************/
// 1、动物类
/***************/
class Animal{
public $name;
public function __construct($name)
{
$this->name = $name;
}
}
/******** 猫继承动物类 **************/
class Cat extends Animal{
public function showInfo()
{
echo '<br> Cat-猫的名字:' .$this->name;
}
}
/******** 狗继承动物类 **************/
class Dog extends Animal{
public function showInfo()
{
echo '<br> Dog-狗的名字:' .$this->name;
}
}
/***************/
// 2、食物类
/***************/
class Food{
public $name;
public function __construct($name)
{
$this->name = $name;
}
}
/******** 鱼继承食物类 **************/
class Fish extends Food{
public function showInfo()
{
echo '<br> Fish-鱼的品种:' .$this->name;
}
}
/******** 骨头继承食物类 **************/
class Bone extends Food{
public function showInfo()
{
echo '<br> Bone-骨头的品种:' .$this->name;
}
}
/***************/
// 3、综合主人类
/***************/
class Master{
public $name;
public function __construct($name)
{
$this->name = $name;
}
/**
* 喂食
* 这里使用类型约束,当我们的类型约束使用的是类(对象),
* 可以使用该类的对象实例和该类的子类对象实例
*/
public function feed(Animal $animal, Food $food)
{
echo '<br> 主人是:' . $this->name;
$animal->showInfo();
echo '<br> 喜欢吃';
$food->showInfo();
}
}
$cat = new Cat('小黑猫');
$dog = new Dog('大花狗');
$fish = new Fish('沙丁鱼');
$bone = new Bone('脆骨');
$master = new Master('贝爷');
// 用master对象喂食
$master->feed($cat, $fish);
echo '<hr>';
$master->feed($dog, $bone);
输出结果
主人是:贝爷
Cat-猫的名字:小黑猫
喜欢吃
Fish-鱼的品种:沙丁鱼
--------------------------------------------------------------------------------------------
主人是:贝爷
Dog-狗的名字:大花狗
喜欢吃
Bone-骨头的品种:脆骨
十一、抽象类
概念:当程序员定义一个类,
该类的一些方法不能确定
,就可以将该方法做成一个抽象方法,这个类就做成一个抽象类
抽象类是用于设计
的,然后需要其它的类来继承并实现抽象类
定义:1、抽象方法
是在方法前使用关键字abstract
来修饰 2、抽象类
是使用abstract
来修饰
abstract class 类名 {
abstract 修饰符 function 函数名(参数列表); //注意这里没有方法体!
}
11.1 抽象方法细节
1、抽象类不能被实例化
2、抽象类可以没有abstract
方法, 抽象类可以有非抽象方法(普通的方法), 成员属性和常量
3、一旦类包含了abstract
方法,则这个类必须声明为abstract
4、抽象方法不能有函数体,即不能有{ }
5、如果一个类继承了某个抽象类,则它必须实现该抽象类的所有抽象方法
.(除非它自己也声明为抽象类)[多级继承]
十二、接口
概念: 接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,再根据具体情况把这些方法写出来
定义:
1、interface
是一个关键字,表示后面是接口
2、接口的命名规范,iXxxxYxxx
, 以i
开头,然后使用大驼峰法
3、接口的方法,全部都是抽象方法,但是不能使用abstract
去修饰
4、接口中可以定义常量const
常量名 = 值
5、一个类可以同时实现多个接口
,使用,
号间隔即可
6、接口中可以有属性,但只能是常量 ,默认是public
, 但不能
用public
显式修饰
7、接口和接口直接可以是继承(extends)
的关系,interface A extends B{ }
interface 接口名{
//属性
//方法
}
小结:
1、类和类之间是
继承
2、类和接口之间是实现
3、接口和接口之间可以是继承
总结: 抽象类和接口的区别
最主要:抽象类是定义方法,但是不知道怎么实现;接口时定义方法让继承的来实现
1、对接口的继承使用implements,抽象类使用extends
2、接口中不可以声明变量,但可以声明类常量.抽象类中可以声明各种变量
3、接口没有构造函数,抽象类可以有
4、接口中的方法默认为public,抽象类中的方法可以用public,protected,private修饰
5、一个类可以继承多个接口,但只能继承一个抽象类
十三、final关键字
场景:如果我们
不希望
某个成员方法
被重写
,则可以将这个方法设置成final
方法,如果我们不希望某个类被继承,则可以设置成final
类
定义:
1、final
是一个关键字,不能修改,不能修饰成员属性
2、如果一个方法被修饰成final
则,该方法不能被子类重写
3、如果一个类被修饰成final
,该类不能被继承
4、什么时候可能使用到,出于安全考虑,不希望其它程序员来继承或者重写重要方法,就可以使用final
5、一般来说,final
类中不会出现final
方法,因为final类都不能被继承,也就不会去重写override final
类的方法了, 但是语法不会报错
6、final
类是可以被实例化
的
final 类名{
//属性
final 访问修饰符 成员方法名(参数列表){
//函数体
}
}