極其精簡的PHP框架WJW

Jim.Wu發表於2017-06-21
最近在做一個專案,使用PHP做後端服務,為了提升程式碼執行效率,自己寫了這個極其精簡的PHP框架,我把它命令為WJW,我的姓名的縮寫
框架中包含連線多個資料庫的實現、連線多個redis的實現,和自動載入呼叫到的類檔案。目標是做到儘量少得執行程式碼、儘量少得載入檔案。
  1. 框架僅支援PDO連線資料庫,不做多種資料庫的支援,也不做多種連線方式的支援;
  2. 框架中運算元據庫的方式和操作redis的方式都使用原生的方法,沒有封裝更多層程式碼,用於減少程式碼的執行路徑;
  3. WJW框架建議把所有可能的自定義類都放到helper目錄中,包括類庫、Model類、service類等等,用於減少使用類檔案時的目錄判斷和框架的程式碼量,開發者可以通過使用類檔案的命令規則區分不同種類的檔案;
  4. WJW框架建議在每一次請求中都儘量少得載入檔案、儘量短的程式碼執行路徑,因為開發者在組織程式碼結構時也需要往這個方向靠攏,才能開發出更加極速高效的系統。

目錄和檔案結構:

helper/  Model類、service類等等類庫的存放目錄,類檔案的檔名和類名需要一致,

      在專案中無需手工例項化類,可以直接使用$app->your_class_name->your_method_name(); 訪問。

------helper_demo.php  這是一個類庫的示例檔案,可以刪除

public/  伺服器中配置虛擬主機時,根目錄指向此目錄,此目錄是對外訪問的入口

------demo.php  這是一個請求介面的示例,可以刪除

base.php  基礎檔案,包含配置檔案、公共函式庫、建立$app例項。

      所有介面首先引入base.php,此檔案中會建立例項$app,

      連線資料庫和redis都通過此例項。

config.php 有些因執行環境(開發、測試、生產)不一樣的配置資訊寫在

      這個檔案中,這個檔案在釋出時不需要釋出。


base.php 程式碼如下:

<?php

/*
 * 基礎檔案,包含配置檔案、公共函式庫、建立$app例項
 * 所有介面首先引入base.php,此檔案中會建立例項$app,連線資料庫和redis都通過此例項
 */

//配置檔案往$config陣列中寫
$config = [];
//有些因執行環境(開發、測試、生產)不一樣的配置資訊寫在config.php中,不跟隨專案釋出
$config = array_merge($config, require('config.php'));

function connectDB($options)
{
    try {
        $pdo = new PDO(
            $options['dsn'],
            $options['username'],
            $options['password'],
            $options['option']
        );
        // 設定 PDO 錯誤模式為異常 ,用於丟擲異常
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        if (isset($options['charset'])) {
            $pdo->exec('SET NAMES "'.$options['charset'].'"');
        }
        return $pdo;
    }
    catch (PDOException $e) {
        throw new Exception($e->getMessage());
    }
}

function connectRedis($options)
{
    $redis = new Redis();
    $redis->pconnect($options['host'], $options['port']);
    return $redis;
}

class wjw
{
    public $db_list = [];
    public $redis_list = [];
    public $helpers = [];
    public function __construct()
    {
    }

    public function __destruct()
    {
        foreach ($this->db_list as $key => &$pdo) {
            $pdo = null;
            unset($this->db_list[$key]);
        }
        foreach ($this->redis_list as $key => &$redis) {
            $redis->close();
            unset($this->redis_list[$key]);
        }
    }

    public function db($db_name='default')
    {
        global $config;
        $db_name = empty($db_name)?'default':$db_name;
        if (!isset($config['db'][$db_name]) ) {
            throw new Exception('資料庫配置不存在:'.$db_name);
        }
        if ( !isset($this->db_list[$db_name]) && isset($config['db'][$db_name]) ) {
            $this->db_list[$db_name] = connectDB($config['db'][$db_name]);
        }
        return $this->db_list[$db_name];
    }

    public function redis($redis_name='default')
    {
        global $config;
        $redis_name = empty($redis_name)?'default':$redis_name;
        if (!isset($config['redis'][$redis_name]) ) {
            throw new Exception('Redis配置不存在:'.$redis_name);
        }
        if ( !isset($this->redis_list[$redis_name]) && isset($config['redis'][$redis_name]) ) {
            $this->redis_list[$redis_name] = connectRedis($config['redis'][$redis_name]);
        }
        return $this->redis_list[$redis_name];
    }

    public function __get($name)
    {
        if (isset($this->helpers[$name])) {
            return $this->helpers[$name];
        }
        if (file_exists(dirname(__FILE__).'/helper/'.$name.'.php')) {
            //helper類檔案的檔名、類名、app中的呼叫方法三者需要一致
            require_once(dirname(__FILE__).'/helper/'.$name.'.php');
            $this->helpers[$name] = new $name;
            return $this->helpers[$name];
        }
        else{
            throw new Exception('helper檔案不存在:'.$name.'.php');
        }
    }
}

$app = new wjw(); 

config.php程式碼如下:

<?php
return [
    'db' => [
        'default' => [
            'dsn'    =>  'mysql:host=127.0.0.1;port=3306;dbname=yourDbName',
            'username'    =>  'yourUsername',
            'password'    =>  'yourPassword',
            'charset'    =>  'utf8',
            'option'    =>  [],
        ]
    ],
    'redis' => [
        'default' => [
            'host'    =>  '127.0.0.1',
            'port'    =>  '6379',
        ]
    ],
]; 

/public/demo.php 程式碼如下:

<?php
/*
 * 介面示例,每個介面一個檔案,或者每類介面一個檔案,原則上是單個檔案越小越好
 * 所有介面首先引入base.php,此檔案中會建立例項$app,連線資料庫和redis都通過此例項
 */
require_once('../base.php');

//使用PHP中PDO的原生方法運算元據庫
讀取一條記錄
$uuid = 763;
$sql = 'SELECT * FROM `users` WHERE `uid` = :uid LIMIT 1';
$stmt = $app->db()->prepare($sql);   
$stmt->execute(array(':uid'=>$uid));
while($row = $stmt->fetch(PDO::FETCH_ASSOC)){      
    print_r($row);
}

//讀取資料列表
$status = 6;
$sql = 'SELECT * FROM `users` WHERE `status` < :status LIMIT 3';
$stmt = $app->db()->prepare($sql);   
$stmt->execute(array(':status'=>$status));
print_r( $stmt->fetchAll(PDO::FETCH_ASSOC));
unset($stmt);

//使用PHP中redis的原生方法操作redis
$app->redis()->set('aaa', 'aaa的值');
$value = $app->redis()->get('aaa');
print_r($value);

//將helper類檔案放入helper目錄中,使用$app->yourClassName 呼叫
//helper類檔案的檔名、類名、app中的呼叫方法三者需要一致
$app->helper_demo->test_helper('測試helper的使用');

/helper/helper_demo.php 程式碼如下:

<?php

class helper_demo
{
    public function __construct()
    {
    }

    public function __destruct()
    {
    }

    public function test_helper($val)
    {
        var_dump($val);
    }
} 

後期可能會增加少量常用函式和類,增加後修改原文內容,也可以在我的個人網站中檢視。

http://www.weinidai.com/index.php/News/detail/id/127

歡迎 phper 們留言評論,指出不足和提出寶貴建議。



相關文章