国强极客
有问题请加微信:guoqiang7585
国强极客

9、php面向对象3 抽象 接口 自动加载 克隆

9、php面向对象3 抽象 接口 自动加载 克隆

最终类和最终方法

1、概述

Final关键字修饰的类,就是最终类;
Final关键字修饰的方法,就是最终方法;

最终类:该类只能实例化,不能被继承。该类十分完善了,不需要升级和扩展。
最终方法:该方法可以被继承,但不能重写。该方法十分完善了,不需要重写了。
最终类,最终方法不能同时使用。

2、实例:最终类和最终方法演示

提示:类是我们自己设计的,我们怎么设计,他们就怎么用。

抽象类和抽象方法

1、概述

abstract关键字修饰的类,就是抽象类;
abstract关键字修饰的方法,就是抽象方法;

抽象类:该类不能直接实例化,必须先继承后再实例化。常用在基础类
抽象方法:方法必须先继承后重写
抽象方法就是方法的命名规范、命名规则、方法大纲,也可以理解为一种监督机制
所有的抽象方法都必须重写,少一个都不行。
抽象方法没有方法体{},必须在子类重写后,再定义方法体。
如果一类中有一个抽象方法,该类必须是抽象类。
抽象方法权限不能是private,因为要先继承再重写。
在PHP7中,抽象方法可以是成员方法,也可以是静态方法。
抽象类中,可以包含其它成员:常量、成员属性、成员方法、静态属性、静态方法。

2、实例:抽象类和抽象方法实例演示

//定义抽象学生类:子类方法的目录大纲
abstract class Student
{
    const TITLE = "PHP第69期就业班";
    //定义成员的抽象方法
    abstract protected function showInfo($a,$b);
    //定义静态的抽象方法
    abstract static public function readMe();
}
//定义传智学生类,并继承学生类
final class ItcastStudent extends Student
{
    //重写showInfo()抽象方法
    public function showInfo($name,$age){
        echo "{$name}的年龄是{$age}岁!<br>";
    }
    //重写readMe()抽象方法
    public static function readMe(){
        echo self::TITLE;
    }
}
//创建传智学生类对象
$obj = new ItcastStudent;
$obj->showInfo("张三四",24);
$obj->readMe();

接口技术

1、接口的基本概念?

接口就是特殊的抽象类。
PHP 类是单继承,也就是不支持多继承。
当一个类需要多个类的功能时,单继承就无能为力了,为此 PHP 引入了类的接口技术。
多人合作开发项目时,需要规范各个功能的名称,就需要用到接口技术。
接口就是一种标准,一种规范。类的功能实现,按照标准接口实现即可;

2、接口定义和实现要点

interface关键字定义接口;
Implements关键字用来实现接口;



接口中方法权限必须是public;
接口中方法默认是抽象的,所以不需要在方法名前面加 abstract ;
接口中方法可以是成员方法,也可以是静态方法;
接口中也可以定义常量,但常量不能重写
类可以实现(implements)多个接口(相当于把多个功能集于一身,如手机实现了小灵通、MP3、MP4的功能);
接口也可以继承(extends)接口,类可以继承(extends)类,但是类只能实现(implements)接口。

3、实例:接口的定义和实现演示

//定义第1个接口InterA
interface InterA
{
    const TITLE = "PHP第69期就业班";
    //定义一个成员抽象方法
    public function showInfo($a,$b);
}

//定义第2个接口InterB
interface InterB
{
    //定义一个静态抽象方法
    public static function readMe();
}

//定义学生类,并实现接口功能
class Student implements InterA,InterB
{
    //重写showInfo()抽象方法
    public function showInfo($name,$age){
        echo "{$name}的年龄是{$age}岁!<br>";
    }
    //重写readMe()抽象方法
    public static function readMe(){
        echo self::TITLE;
    }
}
//创建学生类对象
$obj = new Student();
$obj->showInfo('张三四',26);
$obj->readMe();

4、实例:创建手机类并实现小灵通接口、MP3接口、MP4接口

<?php

//定义小灵通的接口
interface XiaoLingTong
{
    //定义打电话的抽象方法
    public function tel();
}
//定义Mp3接口
interface Mp3
{
    //定义听音乐的抽象方法
    public function music();
}
//定义Mp4接口,并继承Mp3接口
interface Mp4 extends Mp3
{
    //定义看电影的抽象方法
    public function video();
}
//定义手机类,并实现以上所有接口功能
class Mobile implements XiaoLingTong,Mp4
{
    //重写tel()抽象方法
    public function tel(){
        echo "正在打电话!<br>";
    }
    //重写music()抽象方法
    public function music(){
        echo "正在听音乐!<br>";
    }
    //重写video()抽象方法
    public function video(){
        echo "正在看电影!<br>";
    }
    //添加打游戏方法
    public function game(){
        echo "正在打游戏!";
    }
}
//创建手机类对象
$obj = new Mobile();
$obj->tel();
$obj->music();
$obj->video();
$obj->game();

类的自动加载

1、为什么需要类的自动加载

很多开发者写面向对象的应用程序时,对每个类的定义,都建立一个独立的 PHP 类文件,方便类文件的统一管理,这无可厚非。但一个很大的烦恼是,不得不在每个脚本开头,写一个长长的包含文件列表(每个类一个文件)。这样一来,就增加了很多负担、占用了很多的内存,对于后期维护也不方便。

解决方案:按需要加载类文件,而不是把所有类全部包含进来。

2、类文件的命名规范

一个类要单独定义成一个独立的类文件;
类文件扩展名,要以”.class.php“结尾,是一种约定,不是必须的;
类文件主名,要与类名一致;

例如:Db.class.php、UserController.class.php、UserModel.class.php

3、类的自定义加载函数:spl_autoload_register()

PHP7以下版本,使用__autoload()实现类的自动加载;
PHP7以上版本,使用spl_autoload_register()实现类的自动加载。

(1)spl_autoload_register()何时调用?

当试图使用未定义的类时spl_autoload_register自动调用,使用一个类有以下几种情况:
使用new关键字创建不存在类的对象时,spl_autoload_register自动调用;例如:$obj = new Student()
当使用静态化方式访问一个不存在的类时,spl_autoload_register自动调用,例如:Student::show();
继承一个不存在的类时,spl_autoload_register自动调用,例如:class Stu extends Parent{}
实现一个不存在的接口时,spl_autoload_register自动调用,例如:class Stu implements Inter

(2)语法格式

描述:将函数注册到SPL(标准PHP库)的__autoload函数队列中。如果该队列中的函数尚未激活,则激活它们。它实际上创建了 autoload 函数的队列,按定义时的顺序逐个执行。
语法:

bool spl_autoload_register ([ callback $autoload_function ] )

参数:

$autoload_function,欲注册的自动装载函数,可以是匿名函数,也可以是字符串的函数名称。$autoload_function有一个传递过来的类名形参,用于在函数中构建类文件路径。

返回:成功时返回 TRUE, 或者在失败时返回 FALSE。

(3)使用普通函数作为参数

(4)使用匿名函数作为参数

对象克隆

1、什么是对象克隆?

如果已存在了一个对象,而还想再创建一个新对象,并且,两个对象的属性值不一样,或者属性比原来多 ,怎么实现呢? \(obj2 = \)obj1 无法实现!
\(obj2 = \)obj1,这不是复制对象,而是将\(obj1和\)obj2指向了同一个对象地址。
创建新对象有两种方式:a. 使用new关键字; b. 使用 clone 关键字

2、实例:对象克隆的演示

<?php
//定义一个学生类
class Student
{
    private $name = "张三丰";
    private $age  = 24;
    //克隆方法:当对象克隆完成时,自动调用的方法
    public function __clone()
    {
        $this->name = "方俊英";
        $this->age  = 29;
    }
}

//创建学生类对象
$obj1 = new Student();
//克隆对象:将$obj1克隆一份,传给$obj2
//克隆对象,是两个独立的新对象
$obj2 = clone $obj1;
var_dump($obj1,$obj2);

3、实例:魔术方法__clone()在克隆对象中的使用

对象遍历

foreach既可以遍历数组元素,也可以遍历对象属性。

<?php
//定义一个学生类
class Student
{
    protected $name = "张三丰";
    private $age  = 24;
    public  $edu  = "大专";
    //在类内遍历对象属性
    public function showInfo()
    {
        //在类外遍历对象的属性
        echo "<h2>在类内遍历对象的属性</h2>";
        foreach($this as $key=>$value)
        {
            echo "\$this->{$key} = {$value}<br>";
        }       
    }
}
//创建学生类对象
$obj = new Student();
$obj->showInfo();
//在类外遍历对象的属性
echo "<h2>在类外遍历对象的属性</h2>";
foreach($obj as $key=>$value)
{
    echo "\$obj->{$key} = {$value}<br>";
}

常用魔术方法

1、__toString()

描述:将对象转成字符串时,__toString()会自动调用。
语法:

public string __toString ( void )

注意:PHP不支持对象转字符串,因此,不能使用echo输出一个

//定义一个学生类
class Student
{
    protected $name = "张三丰";
    private $age  = 24;
    public  $edu  = "大专";
    //魔术方法__toString():当将对象转成字符串时,自动调用
    public function __toString()
    {
        return "我喝多了!";
    }
}
//创建学生类对象
$obj = new Student();
//将对象转成字符串,然后再输出
echo $obj;

2、__invoke()

描述:当把一个对象当成函数调用时,__invoke()会自动调用。
语法:

mixed __invoke ([ $... ] )
<?php
//定义一个学生类
class Student
{
    protected $name = "张三丰";
    private $age  = 24;
    public  $edu  = "大专";
    //魔术方法__invoke():把对象当成函数调用时,自动调用
    public function __invoke()
    {
        echo "我喝多了!";
    }
}
//创建学生类对象
$obj = new Student();
//将对象当成函数调用时
$obj();

//**********************************************
//数组元素的值,八大数据类型都可以
$arr = array(10,20,30);
$arr[0] = function(){
    echo "OK";
};
//调用函数
$arr[0]();

面向对象的设计模式

1、什么是对象设计模式?

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。

2、常用的设计模式有哪些?

单例设计模式:一个类只能创建一个实例对象,不管用什么办法都无法创建第2个对象;
工厂设计模式:生产不同类对象的工厂;
策略设计模式:定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。
观察者设计模式:定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。

3、单例设计模式的要求(三私一公)

一私:私有的静态的保存对象的属性。
一私:私有的构造方法,阻止类外new对象。
一私:私有的克隆方法,阻止类外clone对象。
一公:公共的静态的创建对象的方法。

//单例设计模式的核心代码
class Db {
    //私有的静态的保存对象的属性
    private static $obj = null;
    //私有的构造方法:阻止类外new对象
    private function __construct(){

    }
    //私有的克隆方法:阻止类外clone对象
    private function __clone(){}
    //公共的静态的创建对象的方法
    public static function getInstance(){
        //判断当前对象是否存在
        if(!self::$obj instanceof self)
        {
            //如果对象不存在,创建并保存它
            self::$obj = new self();
        }
        //返回对象
        return self::$obj;
    }
}
//创建数据库类的对象
$db1 = Db::getInstance();
$db2 = Db::getInstance();
var_dump($db1,$db2);

4、实例:单例设计模式演示Db.class.php


<?php
//定义最终的单例的数据库工具类
class Db
{
    //私有的静态的保存对象的属性
    private static $obj = null;

    //私有的数据库配置信息
    private $db_host; //主机名
    private $db_user; //用户名
    private $db_pass; //密码
    private $db_name; //数据库名
    private $charset; //字符集
    private $link;    //连接对象    

    //私有的构造方法:阻止类外new对象
    private function __construct($config=array())
    {
        $this->db_host = $config['db_host'];
        $this->db_user = $config['db_user'];
        $this->db_pass = $config['db_pass'];
        $this->db_name = $config['db_name'];
        $this->charset = $config['charset'];
        $this->connectDb(); //连接MySQL服务器
        $this->selectDb();  //选择数据库
        $this->setCharset();//设置字符集
    }

    //私有的克隆方法:阻止类外clone对象
    private function __clone(){}

    //公共的静态的创建对象的方法
    public static function getInstance($arr)
    {
        //判断当前对象是否存在
        if(!self::$obj instanceof self)
        {
            //如果对象不存在,创建并保存它
            self::$obj = new self($arr);
        }
        //返回对象
        return self::$obj;
    }

    //私有的连接MySQL服务器方法
    private function connectDb()
    {
        if(!$this->link = @mysqli_connect($this->db_host, $this->db_user, $this->db_pass))
        {
            echo "连接MySQL服务器失败!";
            die();
        }
    }

    //私有的选择数据库的方法
    private function selectDb()
    {
        if(!mysqli_select_db($this->link, $this->db_name))
        {
            echo "选择数据库{$this->db_name}失败!";
            die();
        }
    }

    //私有的设置字符集
    private function setCharset()
    {
        mysqli_set_charset($this->link, $this->charset);
    }

    //公共的析构方法
    public function __destruct()
    {
        mysqli_close($this->link); //断开MySQL连接
    }
}
//创建数据库类的对象
$arr = array(
        'db_host' => 'localhost',
        'db_user' => 'root',
        'db_pass' => '123456',
        'db_name' => 'phpshujuku',
        
        'charset' => 'utf8'
    );
$db1 = Db::getInstance($arr);

课后总结 Xmind

赞赏
对内容有疑问,请加我微信:guoqiang7585
# # # # #
首页      全栈教程      php高级      9、php面向对象3 抽象 接口 自动加载 克隆

国强极客

文章作者

博客站长,有问题请加微信【guoqiang7585】。

国强极客

9、php面向对象3 抽象 接口 自动加载 克隆
最终类和最终方法 1、概述 Final关键字修饰的类,就是最终类; Final关键字修饰的方法,就是最终方法; 最终类:该类只能实例化,不能被继承。该类十分完善了,不需要升级和扩展。 最终方…
扫描二维码继续阅读
2019-08-09