# PHP設計模式
> 在軟件開發過程中,經常出現的典型場景的典型解決方案,稱為設計模式
>
> 是為了程序高內聚、低耦合
>
> 更深入理解面向對象
>
> 有利于開發出擴展性強的程序
## 單例模式
> 用于場景:經典例子是數據庫連接(`redis,mongodb,memcache`等),通過單例模式來實現只做一次`mysql_connect()`來節約資源。
兩個對象是一個的時候,才全等
1. 創建一個普通類
~~~
?class Singleton {
? ? ?
?}
??
?$single = new Singleton();
~~~
2. 封鎖`new`操作,將構造函數私有化
~~~
?class Singleton {
? ? ?private function __construct(){}
?}
~~~
3. 留個靜態方法`getInstance()`來`new`對象
~~~
?class Singleton {
? ? ?private function __construct(){}
? ? ?
? ? ?public static function getInstance()
? ? {
? ? ? ? ?return new self();
? ? }
?}
~~~
4. `getInstance`先頂一個私有靜態屬性來保存實例,第一次保存之后,后面進行判斷這個私有靜態屬性是否為空,否則就直接返回這個存儲實例的私有靜態屬性,此時還有問題,額外定義一個子類繼承這個類,將構造函數改為公有屬性,則還是不行。
~~~
?class Singleton {
? ? ?private static $instance = null;
? ? ?
? ? ?private function __construct(){}
? ? ?
? ? ?public static function getInstance()
? ? {
? ? ? ? ?if (self::$instance === null) {
? ? ? ? ? ? ?self::$instance = new self();
? ? ? ? }
? ? ? ? ?return self::$instance;
? ? }
?}
~~~
5. 用`final`防止繼承時,被修改權限
方法前加`final`,方法不能被覆蓋,類前加`final`,則類不能被繼承
此時,還是有問題,使用`clone`函數時,又產生了一個對象
~~~
?class Singleton {
? ? ?private static $instance = null;
? ? ?
? ? ?final private function __construct(){}
? ? ?
? ? ?public static function getInstance()
? ? {
? ? ? ? ?if (self::$instance === null) {
? ? ? ? ? ? ?self::$instance = new self();
? ? ? ? }
? ? ? ? ?return self::$instance;
? ? }
?}
~~~
6. 可以私有化`__clone()`函數
~~~
?class Singleton {
? ? ?private static $instance = null;
? ? ?
? ? ?final private function __construct(){}
? ? ?
? ? ?public static function getInstance()
? ? {
? ? ? ? ?// 判斷有沒有實例化
? ? ? ? ?if (self::$instance === null) {
? ? ? ? ? ? ?self::$instance = new self();
? ? ? ? }
? ? ? ? ?return self::$instance;
? ? }
? ? ?
? ? ?final private function __clone(){}
?}
~~~
7. 優化后的就是使用`!self::$instance instanceof self`來代替上述的判斷和`final`,這里前者是用來判斷保存的對象不是從本身或者其派生類產生的,這樣就可以避免繼承之后改變構造函數公有化代來的煩惱。也減少了代碼量。
~~~
?<?php
??
?class Singleton
?{
? ? ?private static $instance = null;
??
? ? ?// 私有 => 防止外部進行實例化 new Singleton
? ? ?private function __construct()
? ? {
? ? ? ? ?echo __METHOD__;
? ? }
??
? ? ?public static function getInstance()
? ? {
? ? ? ? ?// 判斷保存的對象不是從本身或者其派生類產生的
? ? ? ? ?if (!self::$instance instanceof self) {
? ? ? ? ? ? ?self::$instance = new self();
? ? ? ? }
? ? ? ? ?return self::$instance;
? ? }
??
? ? ?private function __clone()
? ? {
? ? ? ? ?// TODO: Implement __clone() method.
? ? }
?}
??
?$instance = Singleton::getInstance();
?var_dump($instance);
~~~
運行結果
~~~
?Singleton::__constructobject(Singleton)#1 (0) { }
~~~
## 觀察者模式
> 定義對象間的一種一對多的依賴關系,當一個對象的狀態改變時,所有依賴與它的對象都得到通知并被自動更新
>
> PHP中提供觀察者`observer`與被觀察者`subject`的接口
~~~
?<?php
?/**
? * Created By basic
? * Author: Virus
? * Date: 2020/5/23
? * Time: 21:33
? * 觀察登錄的次數
? */
??
?class User implements SplSubject
?{
? ? ?public $login_num;
? ? ?public $hobby;
??
? ? ?protected $observers = null;
??
? ? ?public function __construct($hobby)
? ? {
? ? ? ? ?$this->login_num = rand(1, 10);
? ? ? ? ?$this->hobby ? ? = $hobby;
? ? ? ? ?$this->observers = new SplObjectStorage();
? ? }
??
? ? ?public function login()
? ? {
? ? ? ? ?// 操作session...
??
? ? ? ? ?// 發送通知
? ? ? ? ?$this->notify();
? ? }
??
? ? ?/**
? ? ? * Attach an SplObserver
? ? ? * @link https://php.net/manual/en/splsubject.attach.php
? ? ? * @param SplObserver $observer <p>
? ? ? * The <b>SplObserver</b> to attach.
? ? ? * </p>
? ? ? * @return void
? ? ? * @since 5.1.0
? ? ? */
? ? ?public function attach(SplObserver $observer)
? ? {
? ? ? ? ?// TODO: Implement attach() method.
? ? ? ? ?$this->observers->attach($observer);
? ? }
??
? ? ?/**
? ? ? * Detach an observer
? ? ? * @link https://php.net/manual/en/splsubject.detach.php
? ? ? * @param SplObserver $observer <p>
? ? ? * The <b>SplObserver</b> to detach.
? ? ? * </p>
? ? ? * @return void
? ? ? * @since 5.1.0
? ? ? */
? ? ?public function detach(SplObserver $observer)
? ? {
? ? ? ? ?// TODO: Implement detach() method.
? ? ? ? ?$this->observers->detach($observer);
? ? }
??
? ? ?/**
? ? ? * Notify an observer
? ? ? * @link https://php.net/manual/en/splsubject.notify.php
? ? ? * @return void
? ? ? * @since 5.1.0
? ? ? */
? ? ?public function notify()
? ? {
? ? ? ? ?// TODO: Implement notify() method.
? ? ? ? ?$this->observers->rewind();
? ? ? ? ?while ($this->observers->valid()) {
? ? ? ? ? ? ?$observer = $this->observers->current();
? ? ? ? ? ? ?$observer->update($this);
? ? ? ? ? ? ?$this->observers->next();
? ? ? ? }
? ? }
?}
??
?class Security implements SplObserver
?{
? ? ?/**
? ? ? * Receive update from subject
? ? ? * @link https://php.net/manual/en/splobserver.update.php
? ? ? * @param SplSubject $subject <p>
? ? ? * The <b>SplSubject</b> notifying the observer of an update.
? ? ? * </p>
? ? ? * @return void
? ? ? * @since 5.1.0
? ? ? */
? ? ?public function update(SplSubject $subject)
? ? {
? ? ? ? ?// TODO: Implement update() method.
? ? ? ? ?if ($subject->login_num >= 3) {
? ? ? ? ? ? ?echo '這是第'.$subject->login_num.'次安全登錄';
? ? ? ? } else {
? ? ? ? ? ? ?echo '這是第'.$subject->login_num.'次登錄,異常';
? ? ? ? }
? ? }
?}
??
?class Ad implements SplObserver
?{
? ? ?/**
? ? ? * Receive update from subject
? ? ? * @link https://php.net/manual/en/splobserver.update.php
? ? ? * @param SplSubject $subject <p>
? ? ? * The <b>SplSubject</b> notifying the observer of an update.
? ? ? * </p>
? ? ? * @return void
? ? ? * @since 5.1.0
? ? ? */
? ? ?public function update(SplSubject $subject)
? ? {
? ? ? ? ?// TODO: Implement update() method.
? ? ? ? ?if ($subject->hobby == 'sports') {
? ? ? ? ? ? ?echo '臺球錦標賽預定';
? ? ? ? } else {
? ? ? ? ? ? ?echo '好好學習,天天向上';
? ? ? ? }
? ? }
?}
??
?$user = new User('study');
?$user->attach(new Security());
?$user->attach(new Ad());
??
?$user->login();
~~~
## 簡單工廠模式
> 這里拿連接多種數據庫來當作案例
>
> 數據庫類一般會有一個連接的接口 ,這是每個數據庫連接的共同的接口`Db`
>
> 按照正常面向接口開發來說,我們不知道各種數據庫類的具體內部細節,只知道,數據庫類都實現了`Db`接口
~~~
?<?php
?/**
? * Created By basic
? * Author: Virus
? * Date: 2020/5/23
? * Time: 18:03
? */
??
?// 共同接口
?interface db
?{
? ? ?function conn();
?}
??
?// 服務端開發(不知道將會被誰調用)
?class DbMysql implements db
?{
? ? ?function conn()
? ? {
? ? ? ? ?// TODO: Implement conn() method.
? ? ? ? ?echo '連接上了mysql';
? ? }
?}
??
?class DbSqlite implements db
?{
? ? ?function conn()
? ? {
? ? ? ? ?// TODO: Implement conn() method.
? ? ? ? ?echo '連接上了sqlite';
? ? }
?}
??
?$db = new DbMysql();
?$db->conn(); // 連接上了mysql
~~~
> 此時我們還是知道服務端有哪些數據庫類,對于面向接口編程來說,這里我們要開始認為,客戶端現在不知道服務端有什么數據庫類!的情況,只知道對方開放了一個`SimpleFactory::createDB()`方法,并且方法允許傳遞數據庫名稱,由此衍生出簡單工廠模式!
~~~
?// ...上述代碼還是必須的內容,這里省略
??
?class SimpleFactory
?{
? ? ?public static function createDB($type)
? ? {
? ? ? ? ?if ($type == 'mysql') {
? ? ? ? ? ? ?return new DbMysql();
? ? ? ? } else if ($type == 'sqlite') {
? ? ? ? ? ? ?return new DbSqlite();
? ? ? ? } else {
? ? ? ? ? ? ?return new Exception("Error db type", 1);
? ? ? ? }
? ? }
?}
??
?$mysql = SimpleFactory::createDB('mysql');
?$mysql->conn();
??
?$sqlite = SimpleFactory::createDB('sqlite');
?$sqlite->conn();
~~~
> 此時,如果新增`Oracle`類型咋辦,一方面,可以直接在上述`if/else`里再來一個`else if`,這樣在`PHP`里修改個5、6條還行,但是對于靜態類語言,他們是需要重新編譯的,所以會很浪費時間。在`OOP`重,重要的開閉原則,對于修改是封閉的,對于擴展時開放的。這就是要我們將工廠也進行擴展,不要輕易去修改內容。
所以我們新增了一個工廠的接口提供了一個`createDB`的方法
~~~
?interface Factory
?{
? ? ?public function createDB();
?}
??
?class MySQLFactory implements Factory
?{
? ? ?public function createDB()
? ? {
? ? ? ? ?// TODO: Implement createDB() method.
? ? ? ? ?return new DbMysql();
? ? }
?}
??
?class SqliteFactory implements Factory
?{
? ? ?public function createDB()
? ? {
? ? ? ? ?// TODO: Implement createDB() method.
? ? ? ? ?return new DbSqlite();
? ? }
?}
??
?// 新增Oracle的方式就變了
?class Oracle implements db
?{
? ? ?function conn()
? ? {
? ? ? ? ?// TODO: Implement conn() method.
? ? ? ? ?echo '連接上了Oracle';
? ? }
?}
?class OracleFactory implements Factory
?{
? ? ?public function createDB()
? ? {
? ? ? ? ?// TODO: Implement createDB() method.
? ? ? ? ?return new Oracle();
? ? }
?}
~~~
## 職責鏈模式(chain of responsibility)
> 每個對象,存儲著對自己上級的引用,如果自己處理不了,就交給上一級
拿舉報信息提交給能處理的人的案例來說
~~~
?<!DOCTYPE html>
?<html lang="en">
?<head>
? ? ?<meta charset="UTF-8">
? ? ?<title>責任鏈模式</title>
?</head>
?<body>
?<h1>責任鏈模式</h1>
?<form action="action.php" method="post">
? ? ?<select name="jubao" id="">
? ? ? ? ?<option value="1">粗口</option>
? ? ? ? ?<option value="2">黃賭毒</option>
? ? ? ? ?<option value="3">分裂國家</option>
? ? ?</select>
? ? ?<button type="submit">提交</button>
?</form>
?</body>
?</html>
~~~
`action.php`
~~~
?<?php
?/**
? * Created By basic
? * Author: Virus
? * Date: 2020/5/23
? * Time: 22:13
? */
??
?header('content-type: text/html;charset=utf-8');
??
?// 版主類
?class Board
?{
? ? ?// 權限
? ? ?public $power = 1;
? ? ?// 上級
? ? ?protected $top = 'Admin';
??
? ? ?public function process($level)
? ? {
? ? ? ? ?// 如果當前的處理者權限不夠,就引導去它的上級去處理
? ? ? ? ?if ($level <= $this->power) {
? ? ? ? ? ? ?echo '版主刪帖子';
? ? ? ? } else {
? ? ? ? ? ? ?$top = new $this->top;
? ? ? ? ? ? ?$top->process($level);
? ? ? ? }
? ? }
?}
??
?class Admin
?{
? ? ?protected $power = 2;
? ? ?protected $top = 'Police';
? ? ?public function process($level)
? ? {
? ? ? ? ?if ($level <= $this->power) {
? ? ? ? ? ? ?echo '管理員封鎖賬號';
? ? ? ? } else {
? ? ? ? ? ? ?$top = new $this->top;
? ? ? ? ? ? ?$top->process($level);
? ? ? ? }
? ? }
?}
??
?class Police
?{
? ? ?protected $power;
? ? ?protected $top = null;
? ? ?public function process($level)
? ? {
? ? ? ? ?echo '警察抓起來';
? ? }
?}
??
?/*
? * 這里還是偏向面向過程的解決方式
?if ($level == 1) {
? ? ?$processer = new Board();
? ? ?$processer->process();
?} else if ($level == 2) {
? ? ?$processer = new Admin();
? ? ?$processer->process();
?} else {
? ? ?$processer = new Police();
? ? ?$processer->process();
?}
?*/
??
?// 責任鏈模式來處理舉報問題
?// 接收舉報等級
?$level = $_POST['jubao'] + 0;
??
?$judge = new Board();
?$judge->process($level);
~~~
## 策略模式
和工廠模式類似
區別:應用場景進行區別
> 工廠中,根據不同的情況返回過來的對象,就干它本身的方法
>
> 策略中,根據不同的情況下返回過來的對象,賦給父類,不必去管返回來的對象。
***案例:***
~~~
?<!DOCTYPE html>
?<html lang="en">
?<head>
? ? ?<meta charset="UTF-8">
? ? ?<title>策略模式</title>
?</head>
?<body>
?<form action="calc.php" method="post">
? ? ?<input type="text" name="num1">
? ? ?<select name="op" id="">
? ? ? ? ?<option value="add">+</option>
? ? ? ? ?<option value="sub">-</option>
? ? ? ? ?<option value="mul">*</option>
? ? ? ? ?<option value="div">/</option>
? ? ?</select>
? ? ?<input type="text" name="num2">
? ? ?<p>
? ? ? ? ?<input type="submit" value="計算">
? ? ?</p>
?</form>
?</body>
?</html>
~~~
~~~
?<?php
?/**
? * Created By basic
? * Author: Virus
? * Date: 2020/5/24
? * Time: 10:31
? */
??
?interface Math
?{
? ? ?public function calc($num1, $num2);
?}
??
?class MathAdd implements Math
?{
? ? ?public function calc($num1, $num2)
? ? {
? ? ? ? ?// TODO: Implement calc() method.
? ? ? ? ?return $num1 + $num2;
? ? }
?}
??
?class MathSub implements Math
?{
? ? ?public function calc($num1, $num2)
? ? {
? ? ? ? ?// TODO: Implement calc() method.
? ? ? ? ?return $num1 - $num2;
? ? }
?}
??
?class MathMul implements Math
?{
? ? ?public function calc($num1, $num2)
? ? {
? ? ? ? ?// TODO: Implement calc() method.
? ? ? ? ?return $num1 * $num2;
? ? }
?}
??
?class MathDiv implements Math
?{
? ? ?public function calc($num1, $num2)
? ? {
? ? ? ? ?// TODO: Implement calc() method.
? ? ? ? ?return $num1 / $num2;
? ? }
?}
??
?// 一般思路,根據op,制造不同對象,并且調用
??
?// 這里我們封裝一個虛擬計算器
??
?class CMath
?{
? ? ?protected $calc = null;
??
? ? ?public function __construct($type)
? ? {
? ? ? ? ?$calc ? ? ? = 'Math'.$type;
? ? ? ? ?$this->calc = new $calc();
? ? }
??
? ? ?public function calc($num1, $num2)
? ? {
? ? ? ? ?return $this->calc->calc($num1, $num2);
? ? }
?}
??
?$type ?= $_POST['op'];
?$cmath = new CMath($type);
?echo $cmath->calc($_POST['num1'], $_POST['num2']);
~~~
## 裝飾器模式(decorator)
> 子類先獲取父類的對象,然后進行修飾
>
> 可以動態地添加修改類地功能
>
> 一個類提供了一項功能,如果要在修改并添加額外地功能,傳統地編程模式,需要寫一個子類繼承它,并重新實現類地方法。
>
> 使用裝飾器模式 ,僅需在運行時添加一個裝飾器對象即可實現,可以實現最大地靈活性。
**裝飾器實現文章的編輯**
~~~
?<?php
?/**
? * Created By basic
? * Author: Virus
? * Date: 2020/5/24
? * Time: 11:46
? */
??
?class BaseArt
?{
? ? ?protected $content;
? ? ?protected $art = null;
??
? ? ?public function __construct($content)
? ? {
? ? ? ? ?$this->content = $content;
? ? }
??
? ? ?public function decorator()
? ? {
? ? ? ? ?return $this->content;
? ? }
?}
??
?// 編輯文章摘要
?class EditorArt extends BaseArt
?{
? ? ?public function __construct(BaseArt $art)
? ? {
? ? ? ? ?$this->art = $art;
? ? ? ? ?$this->decorator();
? ? }
??
? ? ?public function decorator()
? ? {
? ? ? ? ?return $this->content = $this->art->decorator().'小編摘要';
? ? }
?}
??
?class SeoArt extends BaseArt
?{
? ? ?public function __construct(BaseArt $art)
? ? {
? ? ? ? ?$this->art = $art;
? ? ? ? ?$this->decorator();
? ? }
??
? ? ?public function decorator()
? ? {
? ? ? ? ?return $this->content = $this->art->decorator().'seo關鍵詞';
? ? }
?}
??
?$art = new SeoArt(new EditorArt(new BaseArt('好好學習')));
?echo $art->decorator();
??
?// 此時SeoArt和EditorArt屬于兄弟關系
~~~
## 適配器模式
> 沒搞懂有啥意義。。。
暫時給個示例代碼
~~~
?<?php
?/**
? * Created By basic
? * Author: Virus
? * Date: 2020/5/24
? * Time: 15:49
? */
??
?// 適配器模式
??
?// 服務器端代碼
?class Tianqi
?{
? ? ?public static function show()
? ? {
? ? ? ? ?$today = [
? ? ? ? ? ? ?'tep' ?=> 28,
? ? ? ? ? ? ?'wind' => 7,
? ? ? ? ? ? ?'sun' ?=> 'sunny',
? ? ? ? ];
??
? ? ? ? ?return serialize($today);
? ? }
?}
??
?// 增加一個適配器
?class AdapterTianqi extends Tianqi
?{
? ? ?public static function show()
? ? {
? ? ? ? ?$today = parent::show();
? ? ? ? ?$today = unserialize($today);
? ? ? ? ?$today = json_encode($today);
??
? ? ? ? ?return $today;
? ? }
?}
??
?// 客戶端調用
?$tq = unserialize(Tianqi::show());
?echo '溫度:', $tq['tep'], '<br>';
?echo '風力:', $tq['wind'], '<br>';
?echo '太陽:', $tq['sun'], '<br>';
??
??
?// java、python再來調用,通過適配器調用
?$tq1 = AdapterTianqi::show();
?$tq1 = json_decode($tq1);
??
?echo '溫度:', $tq1->tep, '<br>';
?echo '風力:', $tq1->wind, '<br>';
?echo '太陽:', $tq1->sun, '<br>';
~~~
## 橋接模式
消息發送案例
消息分為站內消息、email發送、手機短信發送
消息也分為普通信息、緊急信息、特急信息
傳統方式:M \* N
橋接模式后:M + N可以任意兩兩組合

傳統方式代碼:
~~~
?<?php
?/**
? * Created By basic
? * Author: Virus
? * Date: 2020/5/24
? * Time: 16:08
? */
??
?// 橋接模式
??
?// 論壇給用戶發信息,可以實站內短信,email,手機
??
?interface Message
?{
? ? ?public function send($to, $content);
?}
??
?class Zn implements Message
?{
? ? ?public function send($to, $content)
? ? {
? ? ? ? ?// TODO: Implement send() method.
? ? ? ? ?echo '站內信給', $to, '內容:', $content;
? ? }
?}
??
?class Email implements Message
?{
? ? ?public function send($to, $content)
? ? {
? ? ? ? ?// TODO: Implement send() method.
? ? ? ? ?echo '郵箱給', $to, '內容:', $content;
? ? }
?}
??
?class Sms implements Message
?{
? ? ?public function send($to, $content)
? ? {
? ? ? ? ?// TODO: Implement send() method.
? ? ? ? ?echo '短信給', $to, '內容:', $content;
? ? }
?}
??
?/*
?// 內容也分普通,加急,特急
?class ZnCommon extends Zn{}
?class ZnWarn extends Zn{}
?class ZnDanger extends Zn{}
??
?// 郵箱也分以上等級 。。。
?*/
??
?// 信息發送方式是一個變化因素
?// 信息的緊急程度也是變化因素
?// 不修改父類,只考慮2個因素的組合,不停產生新類,肯定是不行的
~~~
橋接模式代碼
~~~
?<?php
?/**
? * Created By basic
? * Author: Virus
? * Date: 2020/5/24
? * Time: 16:31
? */
??
?abstract class Info
?{
? ? ?protected $send = null;
??
? ? ?public function __construct($send)
? ? {
? ? ? ? ?$this->send = $send;
? ? }
??
? ? ?public abstract function msg($content);
? ? ?public function send($to, $content)
? ? {
? ? ? ? ?$content = $this->msg($content);
? ? ? ? ?$this->send->send($to, $content);
? ? }
?}
??
?class Zn
?{
? ? ?public function send($to, $content)
? ? {
? ? ? ? ?echo '站內給', $to, '內容是:', $content;
? ? }
?}
??
?class Email
?{
? ? ?public function send($to, $content)
? ? {
? ? ? ? ?echo 'Email給', $to, '內容是:', $content;
? ? }
?}
??
?class Sms
?{
? ? ?public function send($to, $content)
? ? {
? ? ? ? ?echo '短信給', $to, '內容是:', $content;
? ? }
?}
??
?class CommonInfo extends Info
?{
? ? ?public function msg($content)
? ? {
? ? ? ? ?return '普通'.$content;
? ? }
?}
??
?class WarnInfo extends Info
?{
? ? ?public function msg($content)
? ? {
? ? ? ? ?return '緊急'.$content;
? ? }
?}
??
?class DangerInfo extends Info
?{
? ? ?public function msg($content)
? ? {
? ? ? ? ?return '特急'.$content;
? ? }
?}
??
?// 用站內發普通信息
?$commonInfo = new CommonInfo(new Zn());
?$commonInfo->send('小明', '吃飯了');
??
?echo '<br/>';
??
?$sms = new DangerInfo(new Sms());
?$sms->send('小剛', '失火了,快回家');
??
~~~
- PHP獲取客戶端瀏覽器信息和版本
- PHP獲取客戶端操作系統信息
- 無限級分類
- git使用
- 權限檢測思路
- Vue學習
- 遇到的一些問題
- PHP的編碼思維和技巧
- mysql復習
- tp5
- ThinkPHP5.x 公共函數
- TP5登錄注冊
- TP5使用模板繼承
- ThinkPHP5.1 清除緩存
- thinkphp5實現安裝程序
- 安全
- tp中實現跨域代碼
- ThinkPHP5.1配合pjax實現菜單欄無刷新跳轉
- 獲取數據庫版本和數據庫大小
- 模型的基本CURD操作
- 商品spu
- 全局異常處理類
- ExceptionHandler
- BaseException
- PHP函數之error_reporting(E_ALL ^ E_NOTICE)詳細說明
- 微信小程序
- wx:for
- tp6
- 分離的一些模塊
- session開啟
- Spring
- 依賴注入
- 數據結構
- 二叉樹
- js獲取地址欄變量
- PHP設計模式
- 面向對象
- PHP1
- PHP性能優化
- Java學習
- static關鍵字
- 多態
- 接口、階乘
- 大佬給的面試題
- 訪問量為5000萬的博客系統設計
- PHP可變參數
- Nginx的配置案例
- 求數組中的最大值,并返回數組索引
- PHP面試方向
- PHP數組工具類ArrUtil
- 字符串工具類StrUtil
- PHP使用curl發送請求
- mysql
- PHP上傳base64圖片處理函數
- webstorm小程序常用配置
- 郵箱正則表達式
- leetcode mysql記錄
- 函數庫