近期学习了面向对象编程中一些比较抽象的概念,在此对部分重点内容的要点做一下整理小结。
1、类的继承,也叫类的扩展(父类: 基类、子类: 扩展类)
二类成员: 子类有权访问的父类成员类型, public, protected
三种操作: 子类对父类的三种操作: 继承, 重写, 扩展
2、抽象类: 部分分离了设计(抽象类中完成)与实现(工作类中完成)
设计类:具体方法,有方法体: {…};抽象方法:没有方法体,
只要一个类中有一个抽象方法, 那么这个类就是:抽象类
实现类/工作类: 是一个可以被实例化的普通类,最终工作类: 允许实例化
工作类不一定是可以被实例化的普通类,也可是一个抽象类
抽象类也可以被继承, 抽象类也可以用在继承的上下文环境中
抽象类中允许有抽象成员, 但不是强制的,也可以没有。
必须将抽象类中的抽象方法实现
3、接口: 完全分离了”设计与实现”,关键字: interface,
使用与类相似的语法: 抽象方法, 常量, 构造方法(魔术方法的一种),
默认访问控制必须是public,接口允许多继承, 从而间接实现了PHP的多继承,implements (英婆慢吃),单接口, 工作类实现接口 接口常量的访问与类常量一样。多接口继承,一个接口同时继承多个接口,接口可以突破php类的继承限制, 允许多继承, 形成了多层级的接口。
用抽象类来部分实现一个接口,接口是实现多态的重要手段。
因为是面向接口编程, DB_PDO, DB_MySQLi都实现了同一接口,只要将对象参数的类型限定在接口上就可以实现多态,至于选用哪个类实例,由用户自行选择。
4、trait: php5.4+, 代码复用,与抽象类,接口一样不能实例化, 只能嵌入到宿主类中使用,它是一个特殊类: 1. 常规, 2. 静态, 3. 抽象, 不能用类常量。
类中使用trait , 用use 关键,将use tDemo理解为加载。
trait 功能1: 代码复用;trait2: 在继承上下文环境中, 具有优先级, 通过优先的设置, 降低单继承的影响。
trait中的同名方法将父类中同名方法覆盖了, 重写了;当前类的同名方法又会覆盖掉trait中同名方法;方法使用的优先级:子类 > trait > 父类。Trait组合的同名方法的命名冲突的解决方案:一是替换,用关键字insteadOf,二是别名,用关键字as,as 还可以修改trait成员的访问控制。
1、实例演示后期静态绑定的原理与实现
<?php
// 后期静态绑定: 又叫延迟静态绑定
// 后期静态绑定工作在: 静态继承上下文的环境中
abstract class CreateInstance
{
}
// 实现类1
class User extends CreateInstance
{
public static function create() : self
{
return new self();
}
}
// 实现类2
class Product extends CreateInstance
{
public static function create() : self
{
return new self();
}
}
// 客户端
$user = User::create();
var_dump($user);
echo '<hr>';
$product = new Product();
var_dump($product);
----------------------
// 将demo1.php中的代码进行简化, 将类实例的创建过程上移到它的基类中
abstract class CreateInstance
{
public static function create()
{
// 出错原因: self 代表当前类,而当前是抽象类, 不能实例化, 不能用new 调用
// 解决:将类的定义与类的调用完全分离开
// 方案: 后期静态绑定, 使用关键字: static, 将self 替换掉
// return new self();
return new static();
// 程序执行有二个过程: 编译, 执行
// 类方法与有一个调用上下文, 定义上下文
// self: self始终与定义该方法(属性)的类进行绑定
// static: static总是自动与该方法(属性)调用类进行绑定
// self: 与定义类绑定
// static: 与调用类绑定
}
}
// 实现类1
class User extends CreateInstance
{
}
// 实现类2
class Product extends CreateInstance
{
}
// 客户端
$user = User::create();
var_dump($user);
echo '<hr>';
$product = Product::create();
var_dump($product);
---------------------
// 后期静态绑定的应用场景: 动态绑定静态成员的调用上下文
// 调用上下文者: 调用者
class Base
{
// 静态方法: 允许重写
public static function index()
{
return '当前调用方法: ' . __METHOD__;
}
public static function fetch()
{
// return self::index();
return static::index();
}
}
class User extends Base
{
// 重写父类中的静态方法: index()
public static function index()
{
return '当前调用方法: ' . __METHOD__;
}
}
// 客户端
// echo Base::fetch();
echo User::fetch();
2、魔术方法之构造方法与析构方法
<?php
// 魔术方法:
// 语法: 类中有一些方法总是使用双下划线开头, 这就叫魔术方法
// 调用者: 由系统根据一定的条件或用户行为, 自动调用/触发, 禁止用户主动调用
// 构造方法: __construct(), 是类的实例化过程中被自动调用, new 的时候
class Scorelist
{
private $course;
private $score;
// 在实例化的时候,自动完成类属性的初始化/赋值,如何做到呢?
// 构造方法: 构造器, 功能就是生成一个新对象
public function __construct($course, $score)
{
// 1. 生成一个新对象/类实例
// $this是由php接管的对象, 不能用户设置, 下面是伪代码,辅助理解
// $this = new self();
// 2. 初始化这个新对象: 给这个新对象添加属性并赋值, 或自动执行某些操作方法
$this->course = $course;
$this->score = $score;
$this->write();
// 3. 返回这个刚刚创建并初始化的对象
// 隐式返回当前新生的类实例, 不用显式返回, 自动完成
// return $this;
}
// 类方法
public function write()
{
echo "$this->course : $this->score 分<hr>";
}
// 析构方法, 没有参数, 销毁/删除一个对象的时候调用
public function __destruct()
{
echo "Destroying " . $this->score ;
}
}
// 客户端
$Scorelist1 = new Scorelist('PHP网络编程', 90);
//var_dump($Scorelist1);
3、实例演示属性重载/拦截器的所有方法
<?php
// 重载: php中的重载与其它语言不同(C++/Java), 称为"访问拦截器"更贴切
// 拦截器: 属性拦截器, 方法拦截器
// 使用场景: 当用户访问一个不存在的或无权限访问属性/方法时, 自动调用
// 访问: 包括二个操作:就是读和写, 或者称为: 查询和设置
// 属性拦截器: __set(), __get(), __isset(), __unset()
class Product
{
private $name;
private $price;
private $taxRate = 0.06;
public function __construct($name, $price)
{
$this->name = $name;
$this->price = $price;
}
// 1. 属性查询拦截器
public function __get($property)
{
// return $this->$property;
// return $property === 'name' ? $this->name : '无权访问';
// 拦截转发器
// 1. 先事先约定一些方法专用于处理属性访问
$method = 'get' . ucfirst($property);
// 2. 转发访问请求
return method_exists($this, $method) ? $this->$method() : null;
}
private function getName()
{
return mb_substr($this->name, 0, 5) . '...';
}
private function getPrice()
{
return $this->price + $this->price * $this->taxRate;
}
// 2. 属性设置拦截器
public function __set($property, $value)
{
$method = 'set' . ucfirst($property);
// 转发访问请求
return method_exists($this, $method) ? $this->$method($value) : null;
}
private function setName($value)
{
$this->name = trim($value);
}
private function setPrice($value)
{
if ($value === null) unset($this->price);
else $this->price = $value * (1-$this->taxRate);
}
// 3. 属性检测拦截器
public function __isset($property)
{
return $property === 'name' ? isset($this->name) : false;
}
// 4. 属性销毁拦截器
public function __unset($property)
{
if ($property === 'price') {
$method = 'set' . ucfirst($property);
// 转发访问请求
if (method_exists($this, $method)) return $this->$method(null) ;
}
}
}
// 客户端
$product = new Product('一坛绍兴女儿红',520);
// 访问了一个无访问权限的类属性
echo $product->name;
echo $product->price;
echo '<hr>';
$product->name = '一辆8手的夏利';
$product->price = 2000;
echo $product->name;
echo $product->price;
echo '<hr>';
echo isset($product->name) ? '存在' : '不存在';
echo isset($product->price) ? '存在' : '不存在';
unset($product->name);
echo $product->name;
unset($product->price);
echo $product->price;
4、实例演示方法重载/拦截器的所有方法
<?php
// 方法拦截器, 其实比属性拦截器更有用
// __call(), __callStatic()
class User
{
// 方法拦截器
public function __call($name, $arguments)
{
printf('方法名: %s , 参数: [%s]', $name, implode(', ', $arguments));
}
// 静态方法拦截器
public static function __callStatic($name, $arguments)
{
printf('静态方法名: %s , 参数: [%s]', $name, implode(', ', $arguments));
}
}
$user = new User();
$user->demo(1,2,3,4);
echo '<br>';
User::demo(6,7,8,9);
本次课程老师从浅显易懂的实例出发,详解介绍了静态绑定与拦截器相关内容,通过回看视频及讲义代码,加深了理解, 并通过修改实现部分代码,同时对前期学习的内容作了阶段性的回顾和整理,感觉非常有必要。