一.静态成员
- 静态成员的优缺点:
优点:
1.存在多个实例,但是静态成员在内存中,只占一份
2.静态成员,执行效率比实例化高缺点:
静态成员不能自动销毁,实例化就会自动销毁
- 静态是多态的一种
- 静态也是可以被继承的
- 子类继承父类,访问父类的静态方法是用子类的 类名:: 进行访问
二.抽象类
- 抽象类也是多态的一种
- 抽象类用于描述一些事物所具有的的特性和行为,但是没有具体实现
- 抽象类,有类也有方法,但是没有实例
- 关键词:abstract 写在class前面
- 抽象类可以继承抽象类
- 继承了抽象类,那么就要把抽象类里面的所有方法都重写,不然会报错
- 如果继承了抽象类,但是不能把所有方法都重写,那么只能把自己也变成抽象类
- 抽象类里可以可以有普通的方法
- 构造方法也可以在抽象类里使用
抽象类:设计类与实现类是分离的,可以为子类提供一些,公用的方法,作为子类重写的模板来使用
创建抽象类
// 创建抽象类
abstract class A
{
// 抽象方法
abstract public function ff1();
abstract public function ff2();
}
// new A(); // 抽象类不能实例化,不能生产出来对象,但是可以通过继承抽象类进行实例化
// 抽象类继承抽象类,
abstract class B extends A
{
// 构造方法在抽象类里使用
protected $name1;
protected $name2;
public function __construct($name1, $name2)
{
$this->name1 = $name1;
$this->name2 = $name2;
}
// 继承了抽象类,抽象类里的所有抽象方法也要重写,
// 如果抽象类方法不全部都重写,那么只能自己也转变为抽象类
// 抽象类里面也可以使用普通方法
public function ff1()
{
return '我是: ' . $this->name1 . ',继承的抽象类A重写ff1';
}
}
// 继承抽象类B 重写B没有重写的方法
class C extends B
{
public function ff2()
{
return '我是: ' . $this->name2 . ',继承的抽象类B重写抽象类A中的ff2';
}
}
$a = new C('ff1', 'ff2');
echo $a->ff1();
echo '<hr>';
echo $a->ff2();
- 输出
三.类常量
- 类里面也有常量,被当成静态的成员
- 有一些数据不能让别人更改的,就会用到常量
- 不能用普通方法访问常量,要用静态方法访问 类名::
类常量关键词:const
常量
class Cl
{
// const 常量关键词
const CL_NAME = '常量';
// 不能用普通方法访问,要用静态访问方法 类名::
public function get_name()
{
return self::CL_NAME;
}
}
echo Cl::CL_NAME;
$obj = new Cl();
echo $obj->get_name();
四.接口
- 接口也是多态的一种,不管是普通类还是抽象类,都是单继承,就是一个子类只能继承一个父类
- 那我们要一个类继承多个类,经过发展,接口实现了这个功能,它可以实现多个父类
- 创建接口关键词: interface 是替换class
- 接口只允许声明两个成员:1.常量,2.抽象方法
- 接口不能继承,如果继承了就和单继承一样了
- 使用接口关键词: implements 实现接口
- 使用多个接口要用英文逗号隔开
使用接口的时候,如果接口里有静态成员,重写的时候也要按照静态的方法写
接口的运用
// 创建抽象类
abstract class A
{
// const 常量
const APP_NAME = 'Mac';
// 抽象方法
abstract public function az($cj);
}
// 关键词 interface 创建接口
interface Cja
{
public static function az_Cja($a);
}
interface Cjb
{
public function pj($b, $c);
// 方法和函数一样,可以接收多个
public function az_CJb($a);
}
// 用关键词 implements 来使用接口
// 使用多个接口,用英文逗号隔开
class B extends A implements Cja, Cjb
{
public function az($a)
{
return '安装成功: ' . $a;
}
// 使用接口,接口里有静态成员,那么重写的时候就要用静态的方法
public static function az_Cja($a)
{
return '安装成功: ' . $a;
}
public function pj($b, $c)
{
return $b . '<hr>' . $c;
}
public function az_CJb($a)
{
return '安装成功: ' . $a;
}
}
$obj = new B();
echo $obj->pj('苹果台式电脑', '苹果笔记本');
echo '<hr>';
echo $obj->az('A安装包');
echo '<hr>';
echo B::az_Cja('B插件包'); // 静态成员用 类名:: 访问
echo '<hr>';
echo $obj->az_CJb('C插件包');
五.后期静态绑定
- 后期静态绑定也叫延迟静态绑定,
- 创建静态类属于前期, 静态::访问类就是后期
- 后期静态绑定关键词:static 和静态成员关键词一样
- 不管实例化谁,用了$this,它就会先找实例化的那个类里的方法
静态继承的时候,是上下文环境,在调用过程中,没有正确识别调用者
后期静态绑定的使用
class A
{
public static function ff()
{
return '这是A类的ff';
}
public function show()
{
// return $this->ff(); // 静态成员不允许用 $this
// return self::ff(); // 访问结果不匹配,要结果对应,实例化谁,就找谁拿结果
return static::ff(); // 后期静态绑定,用 static关键词 替换 self关键词, 可以让实例化与结果匹配
}
}
class B extends A
{
public static function ff()
{
return '这是B类的ff';
}
}
$a = new A(); // 实例化 A
echo $a->ff(); // 返回: 这是A类的ff
echo '<hr>';
$b = new B(); // 实例化 B
echo $b->ff(); // 返回: 这是B类的ff
六.魔术方法
6.1 析构方法
- __construct 构造方法,在new类的时候自动执行
__destruct 析构方法,在类注销(注销结束)的时候自动执行
析构方法
class A
{
public $name;
public function __construct($name)
{
$this->name = $name;
}
// 析构方法是最后结束了执行
public function __destruct()
{
echo '执行完了';
}
}
$a = new A('析构方法');
$name = $a->name;
echo $a->name;
echo '<hr>';
unset($a); // 删除类,,相当于把类执行完了,结束这个类
echo '<hr>';
echo $name;
6.2 属性重载
- __get 获取不可见和未定义的属性,触发这个魔术方法
- __get 有一个参数,就相当于下标一样
- 私有的和受保护的都可以使用
__set 修改成员的时候触发
修改设置需要两个参数
$key 相当于要修改的参数
$value 相当于要修改的值通过返回 $this的key(参数名) = 要修改的值,进行修改
- 不可见属性和未定义属性的获取与修改
class A
{
protected $age;
protected $jimi;
private $name;
public function __construct($name, $age, $jimi)
{
$this->name = $name;
$this->age = $age;
$this->jimi = $jimi;
}
// __get 有一个参数
public function __get($n)
{
// 判断
if ($n == 'name' || $n == 'age') {
// return $name; // 这里的name和 类里的 $name 不是同一个
// __get的参数: 我们要找的成员名字,我们在我们找name它就是name ,它就相当于是数组的下标一样
// return $n;
// $n 代表要找的成员名字
return $this->$n;
}
// 判断它是否存在
// empty 只要是没有值,也会当 true
if (empty($this->$n)) {
return '不存在';
}
return '抱歉,你暂时没有权限';
}
// 设置需要两个参数
public function __set($key, $value)
{
// $key 相当于要修改的参数
// $value 相当于要修改的值
// 通过返回 $this的key(参数名) = 要修改的值,进行修改
return $this->$key = $value;
}
}
$a = new A('科学家', '25', '核心技术');
echo $a->name . ',' . $a->age; // 科学家25
echo '<hr>';
echo $a->jimi; // 抱歉,你暂时没有权限
echo '<hr>';
$a->age = 30; // 修改参数
echo $a->age; // 输出 30
6.3 方法重载
__call 访问未定义的方法时触发
__call 有两个参数
第一个参数: 是访问的方法
第二个参数: 是方法的传值示例
class A
{
public function __call($key, $value)
{
return '方法名: ' . $key . '<br>方法参数: <pre>' . print_r($value, true) . '不存在';
}
}
$a = new A();
echo $a->adds(10, 30, 50);
- 示例图
6.4 访问未定义的静态方法
- __callStatic 访问未定义的静态方法时触发
- 静态触发,就要使用静态方法
没有静态方法访问,就会执行 __callStatic魔术方法
示例
class A
{
// 静态触发的话,就要使用静态方法
public static function __callStatic($key, $value)
{
return '方法名: ' . $key . '<br>方法参数: <pre>' . print_r($value, true) . '不存在';
}
}
// 没有这个静态方法,就会执行 __callStatic 魔术方法
echo A::add(10, 30, 50);
- 示例图
七.关键词与魔术方法
1.关键词:
关键词 | 解释 | |
---|---|---|
const | 定义类常量 | |
extends | 扩展类,用一个类去扩展它的父类(继承类) | |
public | 公开属性或者方法 | |
protected | 受保护的属性或者方法 | |
private | 私有属性或者方法 | |
static | 静态成员 | |
abstract | 抽象类或者方法 | |
interface | 创建接口 | |
implements | 实现接口 | |
final | 类不能被继承 | |
parent:: | 访问父类 | |
$this | 访问本类 | |
self:: | 访问本静态类 | |
namespace | 创建命名空间 |
2.魔术方法
方法 | 描述 | |
---|---|---|
__construct | 构造方法,实例类的时候自动调用 | |
__destruct | 析构方法,类执行完后,自动调用 | |
__call | 在对象中调用一个不可访问方法时调用 | |
__callStatic | 用静态方式中调用一个不可访问方法时调用 | |
__get | 获取不可见和未定义的属性,自动调用 | |
__set | 修改成员的时候,自动调用 | |
__isset | 当对不可访问属性调用 isset()或 empty()时调用 | |
__unset | 当对不可访问属性调用unset()时被调用 | |
__sleep | 执行serialize()时,先调用这个函数 | |
__wakeup | 执行 unserialize()时,先会调用这个函数 | |
__toString | 类被当成字符串的回应方法 | |
__invoke | 调用函数的方式调用一个对象时的回应方法 | |
__set_state | 调用 var_export()导出类时,此静态方法会被调用 | |
__clone | 当对象复制完成时调用 | |
__autoload | 尝试加载未定义的类 | |
__debugInfo | 打印所需调试信息 |