溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

PHP的基礎(chǔ)知識點(diǎn)和基本用法

發(fā)布時(shí)間:2020-07-01 16:50:26 來源:億速云 閱讀:137 作者:元一 欄目:編程語言

本篇文章為大家展示了PHP的基礎(chǔ)知識點(diǎn)和基本用法,代碼簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細(xì)介紹希望你能有所收獲。

一、PHP常用的四種數(shù)據(jù)結(jié)構(gòu)

簡介:spl是php的一個(gè)標(biāo)準(zhǔn)庫。

官方文檔:http://php.net/manual/zh/book.spl.php

<?php

//spl(php標(biāo)準(zhǔn)庫)數(shù)據(jù)結(jié)構(gòu)

/**
 * 棧(先進(jìn)后出)
 */
$stack = new SplStack();
$stack->push('data1');//入棧(先進(jìn)后出)
$stack->push('data2');//入棧
$stack->push('data3');//入棧

echo $stack->pop();//出棧
echo $stack->pop();//出棧
echo $stack->pop();//出棧


/**
 *隊(duì)列(先進(jìn)先出)
 */
$queue = new SplQueue();
$queue->enqueue('data4');//入隊(duì)列
$queue->enqueue('data5');//入隊(duì)列
$queue->enqueue('data6');//入隊(duì)列

echo $queue->dequeue();//出隊(duì)列
echo $queue->dequeue();//出隊(duì)列
echo $queue->dequeue();//出隊(duì)列
echo $queue->dequeue();//出隊(duì)列


/**
 * 堆
 */
$heap = new SplMinHeap();
$heap->insert('data8');//入堆
$heap->insert('data9');//入堆
$heap->insert('data10');//入堆

echo $heap->extract();//從堆中提取數(shù)據(jù)
echo $heap->extract();//從堆中提取數(shù)據(jù)
echo $heap->extract();//從堆中提取數(shù)據(jù)


/**
 * 固定數(shù)組(不論使不使用,都會分配相應(yīng)的內(nèi)存空間)
 */
$array = new SplFixedArray(15);
$array['0'] = 54;
$array['6'] = 69;
$array['10'] = 32;
var_dump($array);

二、PHP鏈?zhǔn)讲僮鞯膶?shí)現(xiàn)(原理)

1、入口文件 index.php

<?php
/**
 * 框架入口文件
 */
define('BASEDIR',__DIR__);//項(xiàng)目根目錄
include BASEDIR.'/Extend/Loader.php';//引入項(xiàng)目自動(dòng)加載類文件
spl_autoload_register('\\Extend\\Loader::autoload');//執(zhí)行自動(dòng)加載函數(shù),完成類的自動(dòng)加載


$db = new \Extend\Database();
$db->where('uid < 100000')->->order('uid desc')->limit(100);

2、自動(dòng)加載類 Loader.php

<?php
namespace Extend;
/**
 * 實(shí)現(xiàn)框架的自動(dòng)加載
 */
class Loader
{
    /**
     * 實(shí)現(xiàn)文件的自動(dòng)載入
     */
    static function autoload($class)
    {
        require BASEDIR.'/'.str_replace('\\','/',$class).'.php';
    }


}

3、數(shù)據(jù)庫類Database.php

注:只是原理,并沒有對方法進(jìn)行具體的封裝,具體的封裝還是看個(gè)人喜好去定鏈?zhǔn)讲樵兊娘L(fēng)格。

<?php
namespace Extend;

class Database
{
    /**
     * 指定查詢條件
     * @param $where
     */
    function where($where)
    {
        return $this;
    }

    /**
     * 指定排序條件
     */
    function order($order)
    {
        return $this;
    }

    /**
     * 指定查詢的限制條數(shù)
     * @param $limit
     */
    function limit($limit)
    {
        return $this;
    }


}

其實(shí)就是對傳過來的條件進(jìn)行重新的底層封裝,然后再把當(dāng)前對象返回,使得可以不斷的鏈?zhǔn)讲樵儭?/p>

三、PHP魔術(shù)方法的使用

在php設(shè)計(jì)模式中,會涉及到很多魔術(shù)方法的使用,這里也對經(jīng)常會用到的魔術(shù)方法進(jìn)行簡單總結(jié)。

1、框架入口文件 index.php

<?php
/**
 * 框架入口文件
 */
define('BASEDIR',__DIR__);//項(xiàng)目根目錄
include BASEDIR.'/Extend/Loader.php';//引入項(xiàng)目自動(dòng)加載類文件
spl_autoload_register('\\Extend\\Loader::autoload');//執(zhí)行自動(dòng)加載函數(shù),完成類的自動(dòng)加載


/**
 * 魔術(shù)方法的使用
 */

# 實(shí)例化Object類
$obj = new \Extend\Object();//當(dāng)前文件不存在這個(gè)類,就會自動(dòng)執(zhí)行自動(dòng)加載函數(shù)去包含相應(yīng)的類文件(即 Extend/Object.php)


# __set 和 __get 對不存在的屬性進(jìn)行接管
$obj->title = 'xiaobudiu'; //當(dāng)對一個(gè)不存在的類屬性賦值時(shí),會自動(dòng)調(diào)用類中定義的__set()
echo $obj->title; //當(dāng)調(diào)用一個(gè)不存在的類屬性時(shí),會自動(dòng)調(diào)用類中定義的__get()


# __call 和 __callStatic 對不存在或者權(quán)限不夠的類方法進(jìn)行接管
$obj->getUserInfo('1000068'); //當(dāng)調(diào)用一個(gè)不存在的類方法時(shí),會調(diào)用__call(),并自動(dòng)將當(dāng)前方法名和參數(shù)傳到__call方法中
\Extend\Object::getOpenId('1000068'); //當(dāng)調(diào)用一個(gè)不存在的類靜態(tài)方法時(shí),會調(diào)用__callStatic(),并自動(dòng)將當(dāng)前方法名和參數(shù)傳遞到__callStatic方法中


# echo或print對象時(shí),由__toString 接管
echo $obj; //當(dāng)echo或print一個(gè)對象時(shí),會自動(dòng)調(diào)用類中定義的__toString方法


# 在php中,如果我們把一個(gè)對象當(dāng)成函數(shù)用,則由__invoke()接管
$obj('xiaobudiu');//當(dāng)我們將一個(gè)對象當(dāng)成函數(shù)用的時(shí)候,會自動(dòng)調(diào)用當(dāng)前類中定義的__invoke()方法

2、 Extend/Object.php

<?php
namespace Extend;
/**
 * 要求類名必須和文件名保持一致,即類名是Object,則所在文件名為Object.php
 * Class Object
 * @package Extend
 */
class Object
{
    protected $array = array();

    /**
     * 在代碼要給未定義的屬性賦值時(shí)調(diào)用,或在類外部修改被private修飾的類屬性時(shí)被調(diào)用
     */
    function __set($name, $value)
    {
        echo "this is __set func";
    }

    /**
     * 當(dāng)在類外部訪問被private或proteced修飾的屬性或訪問一個(gè)類中原本不存在的屬性時(shí)被調(diào)用
     * @param $name
     */
    function __get($name)
    {
        echo "this is __get func";
    }

    /**
     * 當(dāng)試圖調(diào)用不存在的方法或權(quán)限不足時(shí)會觸發(fā)__call()
     * @param $name 調(diào)用不存在的類方法時(shí)那個(gè)不存在的類方法的方法名
     * @param $arguments 調(diào)用不存在的類方法時(shí)傳遞的參數(shù)
     */
    function __call($name, $arguments)
    {
        var_dump($name,$arguments);
    }


    /**
     * 當(dāng)試圖調(diào)用不存在的靜態(tài)方法或權(quán)限不足時(shí)會觸發(fā)__callStatic()
     * @param $name 調(diào)用不存在的靜態(tài)方法時(shí)那個(gè)不存在的方法的方法名
     * @param $arguments 調(diào)用不存在的靜態(tài)方法時(shí)傳遞的參數(shù)
     */
    function __callStatic($name,$arguments)
    {
       var_dump($name,$arguments);
    }

    /**
     * 當(dāng)使用echo或print打印對象時(shí)會調(diào)用__toString()方法將對象轉(zhuǎn)化為字符串
     */
    function __toString()
    {
        echo "this is __toString func";
    }


    /**
     * 對象本身不能直接當(dāng)函數(shù)用,如果被當(dāng)做函數(shù)用,會直接回調(diào)__invoke方法
     * @param $param
     */
    function __invoke($param)
    {
        echo $param."<br>this is __invoke func";
    }


}

四、三種基礎(chǔ)設(shè)計(jì)模式

1、工廠模式

通過傳入?yún)?shù)的不同,來實(shí)例化不同的類。

index.php

<?php
/**
 * 框架入口文件
 */
define('BASEDIR',__DIR__);//項(xiàng)目根目錄
include BASEDIR.'/Extend/Loader.php';//引入項(xiàng)目自動(dòng)加載類文件
spl_autoload_register('\\Extend\\Loader::autoload');//執(zhí)行自動(dòng)加載函數(shù),完成類的自動(dòng)加載

//構(gòu)造實(shí)例化緩存類時(shí)傳入的參數(shù)
$config = array(
    'host' => '127.0.0.1',
    'pass' => 'myRedis&&&'
);
//工廠模式創(chuàng)建cache對象
$cache = Extend\CacheFactory::getCacheObj('redis',$config);
var_dump($cache);

Extend/CacheFactory.php

<?php
namespace Extend;

class CacheFactory
{
    const FILE = 1;
    const MEMCACHE = 2;
    const REDIS = 3;

    static $instance;//定義靜態(tài)屬性,用于存儲對象

    /**
     * 工廠類創(chuàng)建緩存對象
     * @param $type 指定緩存類型
     * @param array $options 傳入緩存參數(shù)
     * @return FileCache|Memcache|RedisCache
     */
    static function getCacheObj($type, array $options)
    {
        switch ($type) {
            case 'file':
            case self::FILE:
                self::$instance = new FileCache($options);
                break;

            case 'memcache':
            case self::MEMCACHE:
                self::$instance = new Memcache($options);
                break;

            case 'redis':
            case self::REDIS:
                self::$instance = new RedisCache($options);
                break;

            default:
                self::$instance = new FileCache($options);
                break;

        }
        return self::$instance;
    }
}

2、單例模式

保證一個(gè)類只實(shí)例化一個(gè)類對象,進(jìn)而減少系統(tǒng)開銷和資源的浪費(fèi)

index.php

<?php
/**
 * 框架入口文件
 */
define('BASEDIR',__DIR__);//項(xiàng)目根目錄
include BASEDIR.'/Extend/Loader.php';//引入項(xiàng)目自動(dòng)加載類文件
spl_autoload_register('\\Extend\\Loader::autoload');//執(zhí)行自動(dòng)加載函數(shù),完成類的自動(dòng)加載

//單例模式創(chuàng)建對象
$obj = Extend\SingleObject::getInstance();
$obj2 = Extend\SingleObject::getInstance();
var_dump($obj,$obj2);//從結(jié)果可以看出,兩個(gè)實(shí)例化的對象其實(shí)是一個(gè)對象

Extend/SingleObject.php

<?php
namespace Extend;

/**
 * 單例模式創(chuàng)建唯一類對象
 * Class SingleObject
 * @package Extend
 */
class SingleObject
{
    //私有的靜態(tài)屬性,用于存儲類對象
    private static $instance = null;

    //私有的構(gòu)造方法,保證不允許在類外 new
    private function __construct(){}

    //私有的克隆方法, 確保不允許通過在類外 clone 來創(chuàng)建新對象
    private function __clone(){}

    //公有的靜態(tài)方法,用來實(shí)例化唯一當(dāng)前類對象
    public static function getInstance()
    {
        if(is_null(self::$instance)){
            self::$instance = new self;
        }
        return self::$instance;
    }

}

3、注冊樹模式

將我們用到的對象注冊到注冊樹上,然后在之后要用到這個(gè)對象的時(shí)候,直接從注冊樹上取下來就好。(就和我們用全局變量一樣方便)

Extend/RegisterTree,php

<?php
namespace Extend;

/**
 * 注冊樹模式
 * Class RegisterTree
 * @package Extend
 */
class RegisterTree
{

    static protected $objects;//靜態(tài)類屬性,用于儲存注冊到注冊樹上的對象

    /**
     * 將對象注冊到注冊樹上
     * @param $alias 對象的別名
     * @param $object 對象
     */
    static function setObject($alias,$object)
    {
        self::$objects[$alias] = $object;
    }


    /**
     * 從注冊樹上取出給定別名相應(yīng)的對象
     * @param $alias 將對象插入到注冊樹上時(shí)寫的別名
     * @return mixed 對象
     */
    static protected function getObject($alias)
    {
        return self::$objects[$alias];
    }

    /**
     * 將對象從注冊樹上刪除
     * @param $alias 將對象插入到注冊樹上時(shí)寫的別名
     */
    public function unsetObject($alias)
    {
        unset(self::$objects[$alias]);
    }

}

五、其他常見的8種PHP設(shè)計(jì)模式

1、適配器模式

將一個(gè)類的接口轉(zhuǎn)換成客戶希望的另一個(gè)接口,適配器模式使得原本的由于接口不兼容而不能一起工作的那些類可以一起工作。
應(yīng)用場景:老代碼接口不適應(yīng)新的接口需求,或者代碼很多很亂不便于繼續(xù)修改,或者使用第三方類庫。

常見的有兩種適配器,分別是類適配器和對象適配器,這里拿更看好的對象適配器舉例:

<?php
namespace Extend;

/**
 * 對象適配器模式具體流程
 * 1、根據(jù)需求定義接口,進(jìn)而滿足新需求功能
 * 2、定義新類,繼承并實(shí)現(xiàn)定義的接口
 * 3、在實(shí)現(xiàn)接口時(shí),原有的功能,只通過原有類對象調(diào)用原有類功能(委托)
 * 4、再根據(jù)需求,在新類中實(shí)現(xiàn)新需求功能
 * 【適用性】
 * (1)你想使用一個(gè)已經(jīng)存在的類,而它的接口不符合你的需求
 * (2)你想創(chuàng)建一個(gè)可以復(fù)用的類,該類可以與其他不相關(guān)的類或不可預(yù)見的類協(xié)同工作
 * (3)你想使用一個(gè)已經(jīng)存在的子類,但是不可能對每一個(gè)都進(jìn)行子類化以匹配它們的接口。對象適配器可以適配它的父類接口(僅限于對
 */


/**
 * 目標(biāo)角色(根據(jù)需求定義含有舊功能加上新功能的接口)
 * Interface Target 我們期望得到的功能類
 * @package Extend
 */
interface Target
{
    public function simpleMethod1();
    public function simpleMethod2();
}

/**
 * 源角色(在新功能提出之前的舊功能類和方法)
 * Class Adaptee
 * @package Extend
 */
class Adaptee
{

    public function simpleMethod1()
    {
        echo 'Adapter simpleMethod1'."<br>";
    }

}

/**
 * 類適配器角色(新定義接口的具體實(shí)現(xiàn))
 * Class Adapter
 * @package Extend
 */
class Adapter implements Target
{

    private $adaptee;

    function __construct()
    {
        //適配器初始化直接new 原功能類,以方便之后委派
        $adaptee = new Adaptee();
        $this->adaptee = $adaptee;
    }

    //委派調(diào)用Adaptee的sampleMethod1方法
    public function simpleMethod1()
    {
        echo $this->adaptee->simpleMethod1();
    }

    public function simpleMethod2()
    {
        echo 'Adapter simpleMethod2'."<br>";
    }

}

/**
 * 客戶端調(diào)用
 */
$adapter = new Adapter();
$adapter->simpleMethod1();
$adapter->simpleMethod2();

2、策略模式

將一組特定的行為和算法封裝成類,以適應(yīng)某些特定的上下文環(huán)境,這種模式就是策略模式,策略模式可以實(shí)現(xiàn)依賴倒置以及控制反轉(zhuǎn)。

實(shí)例舉例:假如一個(gè)電商網(wǎng)站系統(tǒng),針對男性女性用戶要各自跳轉(zhuǎn)到不同的商品類目,并且所有的廣告位展示展示不同的廣告。

index.php

<?php

/**
 * 框架入口文件
 */
define('BASEDIR',__DIR__);//項(xiàng)目根目錄
include BASEDIR.'/Extend/Loader.php';//引入項(xiàng)目自動(dòng)加載類文件
spl_autoload_register('\\Extend\\Loader::autoload');//執(zhí)行自動(dòng)加載函數(shù),完成類的自動(dòng)加載

/**
 * 首頁數(shù)據(jù)控制器
 * Class Index
 */
class Home
{
    /**
     * 最好寫上這個(gè)注釋,告訴phpstorm是對應(yīng)的哪個(gè)接口類,否則雖然程序執(zhí)行正確,但phpstorm識別不了
     * @var \Extend\UserType
     */
    protected $userType;

    /**
     * 首頁展示數(shù)據(jù)
     * 使用策略模式
     * Index constructor.
     */
    function index()
    {
        echo "AD:";
        $this->userType->showAd();
        echo "Category:";
        $this->userType->showCategory();
    }

    /**
     * 策略模式
     * 根據(jù)傳遞的用戶性別展示不同類別數(shù)據(jù)
     * @param \Extend\UserType $userType
     */
    function setUserType(\Extend\UserType $userType)
    {
        $this->userType = $userType;
    }

}

$obj = new Home();
if ($_GET['userType'] == 'female'){
    $userType = new \Extend\FemaleUserType();
} else {
    $userType = new \Extend\MaleUserType();
}
$obj->setUserType($userType);
$obj->index();

Extend/userType.php(定義的接口)

<?php

namespace Extend;

/**
 * 策略模式
 * 定義根據(jù)性別不同展示不同商品類目和廣告接口
 * Interface UserType
 * @package Extend
 */
interface UserType
{
    //顯示廣告
    function showAd();
    //展示類目
    function showCategory();

}

MaleUserType.php、FemaleUserType.php(具體實(shí)現(xiàn)的類 )

<?php

namespace Extend;

/**
 * 定義男性商品類目和廣告位數(shù)據(jù)接口
 * Class MaleUserType
 * @package Extend
 */
class MaleUserType implements UserType
{
    /**
     * 廣告欄數(shù)據(jù)展示
     */
    function showAd()
    {
        echo "this is 男性’s 廣告條目數(shù)據(jù)";
    }

    /**
     * 商品類目數(shù)據(jù)展示
     */
    function showCategory()
    {
        echo "this is 男性’s 商品類目數(shù)據(jù)";
    }

}
<?php

namespace Extend;

/**
 * 定義女性商品類目和廣告位數(shù)據(jù)接口
 * Class FemaleUserType
 * @package Extend
 */
class FemaleUserType implements UserType
{

    /**
     * 廣告欄數(shù)據(jù)展示
     */
    function showAd()
    {
        echo "this is 女性’s 廣告條目數(shù)據(jù)";
    }

    /**
     * 商品類目數(shù)據(jù)展示
     */
    function showCategory()
    {
        echo "this is 女性’s 商品類目數(shù)據(jù)";
    }


}

顯示效果:

PHP的基礎(chǔ)知識點(diǎn)和基本用法

PHP的基礎(chǔ)知識點(diǎn)和基本用法

3、數(shù)據(jù)對象映射模式

將對象和數(shù)據(jù)存儲映射起來,對一個(gè)對象的操作會映射為對數(shù)據(jù)存儲的操作。

下面在代碼中實(shí)現(xiàn)數(shù)據(jù)對象映射模式,我們將實(shí)現(xiàn)一個(gè)ORM類,將復(fù)雜的sql語句映射成對象屬性的操作。并結(jié)合使用數(shù)據(jù)對象映射模式、工廠模式、注冊模式。

-----(1)數(shù)據(jù)庫映射模式簡單實(shí)例實(shí)現(xiàn)

index.php

<?php
/**
 * 框架入口文件
 */
define('BASEDIR',__DIR__);//項(xiàng)目根目錄
include BASEDIR.'/Extend/Loader.php';//引入項(xiàng)目自動(dòng)加載類文件
spl_autoload_register('\\Extend\\Loader::autoload');//執(zhí)行自動(dòng)加載函數(shù),完成類的自動(dòng)加載

//使用數(shù)據(jù)對象映射模式代替寫sql
$user = new Extend\User(25);
$user->name = '小卜丟飯團(tuán)子';
$user->salary = '20000';
$user->city = '浙江省';

Extend/User.php

<?php

namespace Extend;

class User
{
    //對應(yīng)數(shù)據(jù)庫中的4個(gè)字段
    public $id;
    public $name;
    public $salary;
    public $city;
    //存儲數(shù)據(jù)庫連接對象屬性
    protected $pdo;

    public $data;

    function __construct($id)
    {
        $this->id = $id;
        $this->pdo = new \PDO('mysql:host=127.0.0.1;dbname=test','root','123456');
    }

    function __destruct()
    {
        $this->pdo->query("update user set name = '{$this->name}',salary = '{$this->salary}',city = '{$this->city}' where id='{$this->id}'");
    }
}

這樣,執(zhí)行index.php文件,數(shù)據(jù)庫就會發(fā)生相應(yīng)的操作,也就實(shí)現(xiàn)了基本的數(shù)據(jù)對象映射。

-------(2)數(shù)據(jù)庫映射模式復(fù)雜案例實(shí)現(xiàn)

index.php

<?php

/**
 * 框架入口文件
 */
define('BASEDIR',__DIR__);//項(xiàng)目根目錄
include BASEDIR.'/Extend/Loader.php';//引入項(xiàng)目自動(dòng)加載類文件
spl_autoload_register('\\Extend\\Loader::autoload');//執(zhí)行自動(dòng)加載函數(shù),完成類的自動(dòng)加載


class EX
{
    function index()
    {
        //使用數(shù)據(jù)對象映射模式代替寫sql
        $user = Extend\Factory::getUserObj(25);
        $user->name = '小卜丟飯團(tuán)子';
        $user->salary = '20000';
        $user->city = '浙江省';
    }

    function test()
    {
        $user = Extend\Factory::getUserObj(25);
        $user->city = '廣東省';
    }

}

$ex = new EX();
$ex->index();

Extend/Factory.php

<?php

namespace Extend;

class Factory
{
    /**
     * 工廠模式創(chuàng)建數(shù)據(jù)庫對象,單例模式保證創(chuàng)建唯一db對象
     * @return mixed
     */
    static function CreateDatabaseObj()
    {
        $db = Database::getInstance();
        return $db;
    }

    /**
     * 工廠模式創(chuàng)建user對象,注冊樹模式保證創(chuàng)建唯一對象,避免資源浪費(fèi)
     * @param $id
     * @return User|mixed
     */
    static function getUserObj($id)
    {
        $key = 'user'.$id;
        $user = RegisterTree::getObject($key);
        if (!$user) {
            $user = new User($id);
            RegisterTree::setObject($key,$user);
        }
        return $user;
    }
}

Extend/Register.php

<?php

namespace Extend;

/**
 * 注冊樹模式
 * Class RegisterTree
 * @package Extend
 */
class RegisterTree
{
    static protected $objects;//靜態(tài)類屬性,用于儲存注冊到注冊樹上的對象

    /**
     * 將對象注冊到注冊樹上
     * @param $alias 對象的別名
     * @param $object 對象
     */
    static function setObject($alias,$object)
    {
        self::$objects[$alias] = $object;
    }


    /**
     * 從注冊樹上取出給定別名相應(yīng)的對象
     * @param $alias 將對象插入到注冊樹上時(shí)寫的別名
     * @return mixed 對象
     */
    static function getObject($alias)
    {
        return self::$objects[$alias];
    }

    /**
     * 將對象從注冊樹上刪除
     * @param $alias 將對象插入到注冊樹上時(shí)寫的別名
     */
    public function unsetObject($alias)
    {
        unset(self::$objects[$alias]);
    }

}

Extend/User.php

<?php

namespace Extend;

class User
{
    //對應(yīng)數(shù)據(jù)庫中的4個(gè)字段
    public $id;
    public $name;
    public $salary;
    public $city;
    //存儲數(shù)據(jù)庫連接對象屬性
    protected $pdo;

    public $data;

    function __construct($id)
    {
        $this->id = $id;
        $this->pdo = new \PDO('mysql:host=127.0.0.1;dbname=test','root','123456');
    }

    function __destruct()
    {
        $this->pdo->query("update user set name = '{$this->name}',salary = '{$this->salary}',city = '{$this->city}' where id='{$this->id}'");
    }
}

這樣,就實(shí)現(xiàn)了稍復(fù)雜的數(shù)據(jù)對象映射模式和工廠模式、注冊樹模式相結(jié)合的案例。

4、觀察者模式

當(dāng)一個(gè)對象狀態(tài)發(fā)生改變時(shí),依賴它的對象會全部收到通知,并自動(dòng)更新。

場景:一個(gè)事件發(fā)生后,要執(zhí)行一連串更新操作。傳統(tǒng)的編程方式就是在事件的代碼之后直接加入處理邏輯,當(dāng)更新的邏輯增多之后,代碼會變的難以維護(hù)。這種方式是耦合的,侵入式的,增加新的邏輯需要修改事件主體的代碼。觀察者模式實(shí)現(xiàn)了低耦合,非侵入式的通知與更新機(jī)制。

4.1、傳統(tǒng)模式舉例:

<?php

/**
 * 框架入口文件
 */
define('BASEDIR',__DIR__);//項(xiàng)目根目錄
include BASEDIR.'/Extend/Loader.php';//引入項(xiàng)目自動(dòng)加載類文件
spl_autoload_register('\\Extend\\Loader::autoload');//執(zhí)行自動(dòng)加載函數(shù),完成類的自動(dòng)加載


/**
 * 一個(gè)事件的邏輯控制器
 * Class Event
 */
class Event
{
    /**
     * 用戶確認(rèn)訂單
     */
    function firmOrder()
    {
        //這里假設(shè)一個(gè)事件發(fā)生了,比如用戶已經(jīng)完成下單
        echo "用戶已下單<br>";
        //傳統(tǒng)方式是在發(fā)生一個(gè)事件之后直接進(jìn)行一系列的相關(guān)處理,耦合度比較高,比如寫入日志,給用戶發(fā)郵件等等
        echo "在用戶下單之后進(jìn)行的一系列操作<br>";
    }

}

$event = new Event();
$event->firmOrder();

4.2、觀察者模式典型實(shí)現(xiàn)方式:

(1)定義2個(gè)接口:觀察者(通知)接口、被觀察者(主題)接口

(2)定義2個(gè)類,觀察者類實(shí)現(xiàn)觀察者接口、被觀察者類實(shí)現(xiàn)被觀察者接口

(3)被觀察者注冊自己需要通知的觀察者

(4)被觀察者類某個(gè)業(yè)務(wù)邏輯發(fā)生時(shí),通知觀察者對象,進(jìn)而每個(gè)觀察者執(zhí)行自己的業(yè)務(wù)邏輯。

代碼示例:

test.php

<?php
/**
 * 觀察者模式場景描述:
 * 1、購票后記錄文本日志
 * 2、購票后記錄數(shù)據(jù)庫日志
 * 3、購票后發(fā)送短信
 * 4、購票送抵扣卷、兌換卷、積分
 * 5、其他各類活動(dòng)等
 */


/**
 * 觀察者接口
 */
interface TicketObserver
{
    function buyTicketOver($sender, $args); //得到通知后調(diào)用的方法
}

/**
 * 被觀察者接口(購票主題接口)
 */
interface TicketObserved
{
    function addObserver($observer); //提供注冊觀察者方法
}


/**
 * 主體邏輯,繼承被觀察者接口
 * Class BuyTicket
 */
class BuyTicket implements TicketObserved
{

    /**
     * 定義觀察者數(shù)組屬性,用于儲存觀察者
     * @var array
     */
    private $observers = array();


    /**
     * 實(shí)現(xiàn)被觀察者接口定義的方法(添加觀察者)
     * @param $observer 實(shí)例化后的觀察者對象
     */
    public function addObserver($observer)
    {
        $this->observers[] = $observer;
    }


    /**
     * 購票主體方法
     * BuyTicket constructor.
     * @param $ticket 購票排號
     */
    public function buyTicket($ticket)
    {
        //1、根據(jù)需求寫購票邏輯
        //..............

        //2、購票成功之后,循環(huán)通知觀察者,并調(diào)用其buyTicketOver實(shí)現(xiàn)不同業(yè)務(wù)邏輯
        foreach ($this->observers as $observe) {
            $observe->buyTicketOver($this, $ticket); //$this 可用來獲取主題類句柄,在通知中使用
        }

    }

}



/**
 * 購票成功后,發(fā)送短信通知
 * Class buyTicketMSN
 */
class buyTicketMSN implements TicketObserver
{
    public function buyTicketOver($sender, $ticket)
    {
        echo (date ( 'Y-m-d H:i:s' ) . " 短信日志記錄:購票成功:$ticket<br>");
    }
}

/**
 * 購票成功后,記錄日志
 * Class buyTicketLog
 */
class buyTicketLog implements TicketObserver
{
    public function buyTicketOver($sender, $ticket) 
    {
        echo (date ( 'Y-m-d H:i:s' ) . " 文本日志記錄:購票成功:$ticket<br>");
    }
}


/**
 * 購票成功后,贈(zèng)送優(yōu)惠券
 * Class buyTicketCoupon
 */
class buyTicketCoupon implements TicketObserver
{
    public function buyTicketOver($sender, $ticket) 
    {
        echo (date ( 'Y-m-d H:i:s' ) . " 贈(zèng)送優(yōu)惠券:購票成功:$ticket 贈(zèng)送10元優(yōu)惠券1張。<br>");
    }
}


//實(shí)例化購票類
$buy = new BuyTicket();
//添加多個(gè)觀察者
$buy->addObserver(new buyTicketMSN());
$buy->addObserver(new buyTicketLog());
$buy->addObserver(new buyTicketCoupon());
//開始購票
$buy->buyTicket ("7排8號");

瀏覽器顯示結(jié)果:

PHP的基礎(chǔ)知識點(diǎn)和基本用法

5、原型模式

原型模式與工廠模式的作用類似,都是用來創(chuàng)建對象的。但是實(shí)現(xiàn)方式是不同的。原型模式是先創(chuàng)建好一個(gè)原型對象,然后通過clone原型對象來創(chuàng)建新的對象。這樣,就免去了類創(chuàng)建時(shí)重復(fù)的初始化操作。

原型模式適用于大對象的創(chuàng)建,創(chuàng)建一個(gè)大對象需要很大的開銷,如果每次new就會消耗很大,原型模式僅需內(nèi)存拷貝即可。

代碼實(shí)例:

<?php
/**
 * 抽象原型角色
 */
interface Prototype
{
    public function copy();
}

/**
 * 具體原型角色
 */
class ConcretePrototype implements Prototype
{

    private $_name;

    public function __construct($name)
    {
        $this->_name = $name;
    }

    public function setName($name)
    {
        $this->_name = $name;
    }

    public function getName()
    {
        return $this->_name;
    }

    public function copy()
    {
        //深拷貝實(shí)現(xiàn)
         //$serialize_obj = serialize($this); // 序列化
         //$clone_obj = unserialize($serialize_obj); // 反序列化
         //return $clone_obj;

        // 淺拷貝實(shí)現(xiàn)
        return clone $this;
    }

}

/**
 * 測試深拷貝用的引用類
 */
class Demo
{
    public $array;
}


//測試
$demo = new Demo();
$demo->array = array(1, 2);
$object1 = new ConcretePrototype($demo);
$object2 = $object1->copy();

var_dump($object1->getName());
echo '<br />';
var_dump($object2->getName());
echo '<br />';

$demo->array = array(3, 4);
var_dump($object1->getName());
echo '<br />';
var_dump($object2->getName());
echo '<br />';

瀏覽器顯示結(jié)果:

PHP的基礎(chǔ)知識點(diǎn)和基本用法

6、裝飾器模式

可以動(dòng)態(tài)的添加或修改類的功能

一個(gè)類實(shí)現(xiàn)一個(gè)功能,如果要再修改或添加額外的功能,傳統(tǒng)的編程模式需要寫一個(gè)子類繼承它,并重新實(shí)現(xiàn)類的方法。

使用裝飾器模式,僅需在運(yùn)行時(shí)添加一個(gè)裝飾器對象即可實(shí)現(xiàn),可以實(shí)現(xiàn)最大的靈活性。

<?php
/**
 * 裝飾器流程
 * 1、聲明裝飾器接口(裝飾器接口)
 * 2、具體類繼承并實(shí)現(xiàn)裝飾器接口(顏色裝飾器實(shí)現(xiàn),字體大小裝飾器實(shí)現(xiàn))
 * 3、在被裝飾者類中定義"添加裝飾器"方法(EchoText類中的addDecorator方法)
 * 4、在被裝飾者類中定義調(diào)用裝飾器的方法(EchoText類中的beforeEcho和afterEcho方法)
 * 5、使用時(shí),實(shí)例化被裝飾者類,并傳入裝飾器對象(比如new ColorDecorator('yellow'))
 */

/**
 * 裝飾器接口
 * Class Decorator
 */
interface Decorator
{
    public function beforeEcho();
    public function afterEcho();
}

/**
 * 顏色裝飾器實(shí)現(xiàn)
 * Class ColorDecorator
 */
class ColorDecorator implements Decorator
{
    protected $color;

    public function __construct($color)
    {
        $this->color = $color;
    }

    public function beforeEcho()
    {
        echo "<dis style='color: {$this->color}'>";
    }

    public function afterEcho()
    {
        echo "</p>";
    }
}

/**
 * 字體大小裝飾器實(shí)現(xiàn)
 * Class SizeDecorator
 */
class SizeDecorator implements Decorator
{
    protected $size;

    public function __construct($size)
    {
        $this->size = $size;
    }

    public function beforeEcho()
    {
        echo "<dis style='font-size: {$this->size}px'>";
    }

    public function afterEcho()
    {
        echo "</p>";
    }
}

/**
 * 被裝飾者
 * 輸出一個(gè)字符串
 * 裝飾器動(dòng)態(tài)添加功能
 * Class EchoText
 */
class EchoText
{
    protected $decorators = array();//存放裝飾器

    //裝飾方法
    public function Index()
    {
        //調(diào)用裝飾器前置操作
        $this->beforeEcho();
        echo "你好,我是裝飾器。";
        //調(diào)用裝飾器后置操作
        $this->afterEcho();
    }

    //添加裝飾器
    public function addDecorator(Decorator $decorator)
    {
        $this->decorators[] = $decorator;
    }

    //執(zhí)行裝飾器前置操作 先進(jìn)先出原則
    protected function beforeEcho()
    {
        foreach ($this->decorators as $decorator)
            $decorator->beforeEcho();
    }

    //執(zhí)行裝飾器后置操作 先進(jìn)后出原則
    protected function afterEcho()
    {
        $tmp = array_reverse($this->decorators);
        foreach ($tmp as $decorator)
            $decorator->afterEcho();
    }
}

//實(shí)例化輸出類
$echo = new EchoText();
//增加裝飾器
$echo->addDecorator(new ColorDecorator('yellow'));
//增加裝飾器
$echo->addDecorator(new SizeDecorator('22'));
//輸出
$echo->Index();

7、迭代器模式

在不需要了解內(nèi)部實(shí)現(xiàn)的前提下,遍歷一個(gè)聚合對象的內(nèi)部元素而又不暴露該對象的內(nèi)部表示,這就是PHP迭代器模式的定義。

相對于傳統(tǒng)編程模式,迭代器模式可以隱藏遍歷元素的所需的操作。

index.php

<?php
/**
 * 框架入口文件
 */
define('BASEDIR',__DIR__);//項(xiàng)目根目錄
include BASEDIR.'/Extend/Loader.php';//引入項(xiàng)目自動(dòng)加載類文件
spl_autoload_register('\\Extend\\Loader::autoload');//執(zhí)行自動(dòng)加載函數(shù),完成類的自動(dòng)加載

$users = new Extend\AllUser();
//循環(huán)遍歷出所有用戶數(shù)據(jù)
foreach ($users as $user) {
    var_dump($user);
}

Extend/AllUser.php

<?php
namespace Extend;

/**
 * 迭代器模式,繼承php內(nèi)部自帶的迭代器接口(\Iterator)
 * Class AllUser
 * @package Extend
 */
class AllUser implements \Iterator
{
    protected $index = 0;//表示索引
    protected $ids = array();//用于儲存所有user的id(實(shí)際應(yīng)用中,可以采用注冊樹模式進(jìn)行存儲)
    protected $pdo;//用于存儲數(shù)據(jù)庫對象

    function __construct()
    {
        //獲取pdo數(shù)據(jù)庫對象
        $this->pdo = new \PDO('mysql:host=127.0.0.1;dbname=test','root','123456');
        //獲取所有用戶的id
        $this->ids = $this->pdo->query("select id from user")->fetchAll(2);
    }

    /**
     * 實(shí)現(xiàn)接口方法,重置迭代器,回到集合開頭
     */
    public function rewind()
    {
        $this->index = 0;
    }

    /**
     * 實(shí)現(xiàn)接口方法,獲取當(dāng)前元素
     * @return mixed|void
     */
    public function current()
    {
        $id = $this->ids[$this->index]['id'];
        //獲取當(dāng)前用戶的數(shù)據(jù)
        $user_data = $this->pdo->query("select * from user where id='{$id}'")->fetch(2);
        return $user_data;
    }

    /**
     * 實(shí)現(xiàn)接口方法,獲取當(dāng)前元素鍵值
     * @return mixed|void
     */
    public function key()
    {
        return $this->index;
    }

    /**
     * 實(shí)現(xiàn)接口方法,獲取下一個(gè)元素
     */
    public function next()
    {
        $this->index++;
    }

    /**
     * 實(shí)現(xiàn)接口方法,驗(yàn)證是否還有下一個(gè)元素
     * @return bool|void
     */
    public function valid()
    {
        return $this->index < count($this->ids);
    }

}

8、代理模式

在客戶端與實(shí)體之間建立一個(gè)代理對象(proxy),客戶端對實(shí)體進(jìn)行操作全部委派給代理對象,隱藏實(shí)體的具體實(shí)現(xiàn)細(xì)節(jié)。

典型的應(yīng)用就是mysql的主從結(jié)構(gòu),讀寫分離。在mysql中,對所有讀的操作請求從庫,所有寫的操作請求主庫。

聲明一個(gè)代理類,前臺使用時(shí)只需創(chuàng)建一個(gè)代理類,調(diào)用對應(yīng)方法即可。代碼實(shí)例:

index.php

<?php
/**
 * 框架入口文件
 */
define('BASEDIR',__DIR__);//項(xiàng)目根目錄
include BASEDIR.'/Extend/Loader.php';//引入項(xiàng)目自動(dòng)加載類文件
spl_autoload_register('\\Extend\\Loader::autoload');//執(zhí)行自動(dòng)加載函數(shù),完成類的自動(dòng)加載

// 1、傳統(tǒng)編程模式是手動(dòng)選擇
#查詢操作使用從庫
//$db_slave = Extend\Factory::getDatabase('slave');
//$info = $db_slave->query("select * from user where id = 1 limit 1");
#增刪改操作使用主庫
//$db_master = Extend\Factory::getDatabase('master');
//$db_master->query("update user name = 'xiaobudiu' where id = 29 limit 1");


// 2、使用代理模式
$db_proxy = new Extend\Proxy();
$db_proxy->getUserName(1);
$db_proxy->setUserName(29,'xiaobudiu');

Extend/Proxy.php

<?php
namespace Extend;

class Proxy implements IUserProxy
{
    function getUserName($id)
    {
        $db = Factory::getDatabase('slave');
        $db->query("select name from user where id =$id limit 1");
    }

    function setUserName($id, $name)
    {
        $db = Factory::getDatabase('master');
        $db->query("update user set name = $name where id =$id limit 1");
    }
}

Extend/Factory.php

<?php
namespace Extend;

class Factory
{
    static function getDatabase($id)
    {
        $key = 'database_'.$id;
        if ($id == 'slave')
        {
            $slaves = Application::getInstance()->config['database']['slave'];
            $db_conf = $slaves[array_rand($slaves)];
        } else {
            $db_conf = Application::getInstance()->config['database'][$id];
        }
        //注冊樹模式存儲及獲取對象
        $db = Register::get($key);
        if (!$db) {
            $db = new Database\MySQLi();
            $db->connect($db_conf['host'], $db_conf['user'], $db_conf['password'], $db_conf['dbname']);
            Register::set($key, $db);
        }
        return $db;
    }

}

Extend/Application.php

<?php
namespace Extend;

class Application
{
    public $base_dir;
    protected static $instance;

    public $config;

    protected function __construct($base_dir)
    {
        $this->base_dir = $base_dir;
        $this->config = new Config($base_dir.'/configs');
    }

    static function getInstance($base_dir = '')
    {
        if (empty(self::$instance))
        {
            self::$instance = new self($base_dir);
        }
        return self::$instance;
    }
    
}

Extend/Config.php

<?php
namespace Extend;

/**
 * 配置類,繼承于php自帶的ArrayAccess接口
 * 允許一個(gè)對象以數(shù)組的方式訪問
 * Class Config
 * @package Extend
 */
class Config implements \ArrayAccess
{
    protected $path;
    protected $configs = array();

    function __construct($path)
    {
        $this->path = $path;
    }

    function offsetGet($key)
    {
        if (empty($this->configs[$key]))
        {
            $file_path = $this->path.'/'.$key.'.php';
            $config = require $file_path;
            $this->configs[$key] = $config;
        }
        return $this->configs[$key];
    }

    function offsetSet($key, $value)
    {
        throw new \Exception("cannot write config file.");
    }

    function offsetExists($key)
    {
        return isset($this->configs[$key]);
    }

    function offsetUnset($key)
    {
        unset($this->configs[$key]);
    }
}

configs/database.php

<?php
$config = array(
    'master' => array(
        'type' => 'MySQL',
        'host' => '127.0.0.1',
        'user' => 'root',
        'password' => '123456',
        'dbname' => 'test',
    ),
    'slave' => array(
        'slave1' => array(
            'type' => 'MySQL',
            'host' => '127.0.0.1',
            'user' => 'root',
            'password' => '123456',
            'dbname' => 'test',
        ),
        'slave2' => array(
            'type' => 'MySQL',
            'host' => '127.0.0.1',
            'user' => 'root',
            'password' => '123456',
            'dbname' => 'test',
        ),
    ),
);
return $config;

五、面向?qū)ο缶幊痰幕驹瓌t

1、單一職責(zé)原則:一個(gè)類只需要做好一件事情。不要使用一個(gè)類完成很多功能,而應(yīng)該拆分成更多更小的類。

2、開放封閉原則:一個(gè)類寫好之后,應(yīng)該是可擴(kuò)展而不可修改的。

3、依賴倒置原則:一個(gè)類不應(yīng)該強(qiáng)依賴另外一個(gè)類,每個(gè)類對于另外一個(gè)類都是可替換的。

4、配置化原則:盡量使用配置,而不是硬編碼。

5、面向接口編程原則:只需要關(guān)心某個(gè)類提供了哪些接口,而不需要關(guān)心他的實(shí)現(xiàn)。

六、自動(dòng)加載配置類文件

1、php中使用ArrayAccess實(shí)現(xiàn)配置文件的加載(使得程序可以以數(shù)組的方式進(jìn)行讀取配置)

(1)定義Config.php,繼承php自帶的ArrayAccess接口,并實(shí)現(xiàn)相應(yīng)的方法,用于讀取和設(shè)置配置

Extend/Config.php

<?php
namespace Extend;

/**
 * 配置類,繼承于php自帶的ArrayAccess接口
 * 允許一個(gè)對象以數(shù)組的方式訪問
 * Class Config
 * @package Extend
 */
class Config implements \ArrayAccess
{
    protected $path;
    protected $configs = array();

    function __construct($path)
    {
        $this->path = $path;
    }

    function offsetGet($key)
    {
        if (empty($this->configs[$key]))
        {
            $file_path = $this->path.'/'.$key.'.php';
            $config = require $file_path;
            $this->configs[$key] = $config;
        }
        return $this->configs[$key];
    }

    function offsetSet($key, $value)
    {
        throw new \Exception("cannot write config file.");
    }

    function offsetExists($key)
    {
        return isset($this->configs[$key]);
    }

    function offsetUnset($key)
    {
        unset($this->configs[$key]);
    }
}

(2)configs/database.php

<?php
$config = array(
    'master' => array(
        'type' => 'MySQL',
        'host' => '127.0.0.1',
        'user' => 'root',
        'password' => '123456',
        'dbname' => 'test',
    ),
    'slave' => array(
        'slave1' => array(
            'type' => 'MySQL',
            'host' => '127.0.0.1',
            'user' => 'root',
            'password' => '123456',
            'dbname' => 'test',
        ),
        'slave2' => array(
            'type' => 'MySQL',
            'host' => '127.0.0.1',
            'user' => 'root',
            'password' => '123456',
            'dbname' => 'test',
        ),
    ),
);
return $config;

(3)讀取配置

index.php

<?php
/**
 * 框架入口文件
 */
define('BASEDIR',__DIR__);//項(xiàng)目根目錄
include BASEDIR.'/Extend/Loader.php';//引入項(xiàng)目自動(dòng)加載類文件
spl_autoload_register('\\Extend\\Loader::autoload');//執(zhí)行自動(dòng)加載函數(shù),完成類的自動(dòng)加載

$config = new Extend\Config(__DIR__.'/configs');
var_dump($config['database']);

(4)瀏覽器顯示:

PHP的基礎(chǔ)知識點(diǎn)和基本用法

到此,就可以在程序中隨心所欲的加載配置文件了。

2、在工廠方法中讀取配置,生成可配置化的對象

Extend/Factory.php

<?php
namespace Extend;

class Factory
{
    static function getDatabase($id)
    {
        $key = 'database_'.$id;
        if ($id == 'slave')
        {
            $slaves = Application::getInstance()->config['database']['slave'];
            $db_conf = $slaves[array_rand($slaves)];
        } else {
            $db_conf = Application::getInstance()->config['database'][$id];
        }
        //注冊樹模式存儲及獲取對象
        $db = Register::get($key);
        if (!$db) {
            $db = new Database\MySQLi();
            $db->connect($db_conf['host'], $db_conf['user'], $db_conf['password'], $db_conf['dbname']);
            Register::set($key, $db);
        }
        return $db;
    }

}

Extend/Application.php

<?php
namespace Extend;

class Application
{
    public $base_dir;
    protected static $instance;

    public $config;

    protected function __construct($base_dir)
    {
        $this->base_dir = $base_dir;
        $this->config = new Config($base_dir.'/configs');
    }

    static function getInstance($base_dir = '')
    {
        if (empty(self::$instance))
        {
            self::$instance = new self($base_dir);
        }
        return self::$instance;
    }

}

Extend/Config.php

<?php
namespace Extend;

/**
 * 配置類,繼承于php自帶的ArrayAccess接口
 * 允許一個(gè)對象以數(shù)組的方式訪問
 * Class Config
 * @package Extend
 */
class Config implements \ArrayAccess
{
    protected $path;
    protected $configs = array();

    function __construct($path)
    {
        $this->path = $path;
    }

    function offsetGet($key)
    {
        if (empty($this->configs[$key]))
        {
            $file_path = $this->path.'/'.$key.'.php';
            $config = require $file_path;
            $this->configs[$key] = $config;
        }
        return $this->configs[$key];
    }

    function offsetSet($key, $value)
    {
        throw new \Exception("cannot write config file.");
    }

    function offsetExists($key)
    {
        return isset($this->configs[$key]);
    }

    function offsetUnset($key)
    {
        unset($this->configs[$key]);
    }
}

上述內(nèi)容就是PHP的基礎(chǔ)知識點(diǎn)和基本用法,你們學(xué)到知識或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識儲備,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

php
AI