1. 程式人生 > 實用技巧 >面試之後才知道,swoole完美支援TP5?!

面試之後才知道,swoole完美支援TP5?!

協程是什麼

協程可以理解為純使用者態的執行緒,其通過協作而不是搶佔來進行切換,相對於程序或者執行緒,協程所有的操作都可以在使用者態完成,建立和切換的消耗更低,Swoole 可以為每一個請求建立對應的協程,根據 IO 的狀態來合理的排程協程。

在 Swoole 4.x 中,協程(Coroutine)取代了非同步回撥,成為 Swoole 官方推薦的程式設計方式。Swoole 協程解決了非同步回撥程式設計困難的問題,使用協程可以以傳統同步程式設計的方法編寫程式碼,底層自動切換為非同步 IO,既保證了程式設計的簡單性,又可藉助非同步 IO,提升系統的併發能力。

完美支援TP5,首先開啟swoole的http服務

開啟swoole的http服務並設定提供給url訪問頁面的檔案的根目錄,

程式碼如下。這樣在瀏覽器只能訪問…static下面的檔案,而無法訪問其他目錄下的檔案。

http.server

<?php
//開啟http server
$http = new swoole_http_server("0.0.0.0", 9905);
$http->set(
    [
        'enable_static_handler' => true,
        'document_root' => "/usr/local/openresty/nginx/html/swoole/LiveRadio/public/static",
        'worker_num' => 5
    ]
);
$http->on('request', function($request, $response) {
    $response->end("sss". json_encode($request->get));
});

$http->start();

swoole有一個事件回撥函式onWorkStart,此事件在Worker程序/Task程序啟動時發生。這裡建立的物件可以在程序生命週期內使用。

原型:

function onWorkerStart(swoole_server $server, int workerid);

(1)onWorkerStart/onStart是併發執行的,沒有先後順序;

(2)可以通過server->taskworker屬性來判斷當前是Worker程序還是Task程序;

(3)設定了worker_num和task_worker_num超過1時,每個程序都會觸發一次onWorkerStart事件,可通過判斷$worker_id區分不同的工作程序;

(4)由 worker 程序向 task 程序傳送任務,task 程序處理完全部任務之後通過onFinish回撥函式通知worker 程序。

例如,我們在後臺操作向十萬個使用者群發通知郵件,操作完成後操作的狀態顯示為傳送中,這時我們可以繼續其他操作。等郵件群發完畢後,操作的狀態自動改為已傳送。

在onWorkerStart中載入框架的核心檔案後:

(1)不用每次請求都載入框架核心檔案,提高效能;

(2)可以在後續的回撥事件中繼續使用框架的核心檔案或者類庫。

專案目錄下的public資料夾下的index.php是入口檔案,原始碼如下:

<?php
// [ 應用入口檔案 ]
// 定義應用目錄
define('APP_PATH', __DIR__ . '/../application/');
// 載入框架引導檔案
require __DIR__ . '/../thinkphp/start.php';

這個檔案載入了…thinkphp/start.php’,start.php載入了一個核心檔案base.php,所以我們需要把base.php檔案載入到onWorkStart回撥函式裡面,每個worker程序都會觸發一次onWorkerStart事件,因此ThinkPHP框架內的入口檔案等內容就能載入入我們的專案。

修改http.server如下:

<?php
//開啟http server
$http = new swoole_http_server("0.0.0.0", 9906);
$http->set(
    [
        'enable_static_handler' => true,
        'document_root' => "/usr/local/openresty/nginx/html/swoole/LiveRadio/public/static",
        'worker_num' => 5  //設定worker程序數
    ]
);

$http->on('WorkerStart', function (swoole_server $server, $worker_id){
    //定義應用目錄
    define('APP_PATH', __DIR__ . '/../application/');
    // 載入基礎檔案
    //這裡不直接載入start.php的原因是start.php中的程式碼會直接執行,也就是application\index\controller\Index.php檔案(框架的預設首頁)
    /*
     * Container::get('app', [defined('APP_PATH') ? APP_PATH : ''])
    ->run()
    ->send();
    */
    require __DIR__ . '/../thinkphp/base.php';
});

$http->on('request', function($request, $response){
    //適配
    /*
     *由於swoole http提供的API和原生php程式碼是有所不同的,比如原生php中獲取get引數為直接從全域性陣列_GET中獲取,而swoole http中是通過$request->get()的方式獲取,因此要轉換成原生的
     * */

    $_SERVER = [];
    if(isset($request->server)){
        foreach($request->header as $k => $v){
            $_SERVER[strtoupper($k)] = $v;
        }
    }
    $_GET = [];
    if(isset($request->get)){
        foreach($request->get as $k => $v){
            $_GET[$k] = $v;
        }
    }
    $_POST = [];
    if(isset($request->post)){
        foreach($request->post as $k => $v){
            $_POST[$k] = $v;
        }
    }

    //..其餘引數用到的繼續往後寫

    ob_start();
    // 執行應用並響應
    try {
        think\Container::get('app', [APP_PATH])
            ->run()
            ->send();
    }catch (\Exception $e){
        //todo
    }
    $res = ob_get_contents();
    ob_end_clean();
    $response->end($res);
});

$http->start();

此時,用瀏覽器訪問 http://ip:port/?s=index/index/index 可以看到ThinkPHP的預設首頁,但是發現訪問不到http://ip:port/?s=index/index/hello?name=world頁面。

可以打印出路由看看。在專案目錄\thinkphp\library\think\App.php檔案中的routeCheck介面,列印path變數,可以看到url改變後path變數並沒有改變。這是因為onWorkerStart程序載入框架的時候就複用了類成員變數。

    /**
     * URL路由檢測(根據PATH_INFO)
     * @access public
     * @return Dispatch
     */
    public function routeCheck()
    {
        $path = $this->request->path();
        echo "path:".$path."<br/>";
//        var_dump($this->request);
        $depr = $this->config('app.pathinfo_depr');

        // 路由檢測
        $files = scandir($this->routePath);
        foreach ($files as $file) {
            if (strpos($file, '.php')) {
                $filename = $this->routePath . DIRECTORY_SEPARATOR . $file;
                // 匯入路由配置
                $rules = include $filename;
                if (is_array($rules)) {
                    $this->route->import($rules);
                }
            }
        }

        // 是否強制路由模式
        $must = !is_null($this->routeMust) ? $this->routeMust : $this->config('app.url_route_must');

        // 路由檢測 返回一個Dispatch物件
        return $this->route->check($path, $depr, $must, $this->config('app.route_complete_match'));
    }

修改:

進入 專案目錄\thinkphp\library\think\Request.php中

(1)找到function path() { },登出判斷,不再複用類成員變數 $ this->path。

(2)找到function pathinfo() { },登出判斷,不再複用類成員變數$this->pathinfo。

(3)使其支援pathinfo路由,在function pathinfo() { }中新增程式碼

if (isset($_SERVER['PATH_INFO']) && $_SERVER['PATH_INFO'] != '/') {
    return ltrim($_SERVER['PATH_INFO'], '/');
}

此時用瀏覽器訪問:

點關注,不迷路

好了各位,以上就是這篇文章的全部內容了,能看到這裡的人呀,都是人才。之前說過,PHP方面的技術點很多,也是因為太多了,實在是寫不過來,寫過來了大家也不會看的太多,所以我這裡把它整理成了PDF和文件,如果有需要的可以

點選進入暗號: PHP+「平臺」


更多學習內容可以訪問【對標大廠】精品PHP架構師教程目錄大全,只要你能看完保證薪資上升一個臺階(持續更新)

以上內容希望幫助到大家,很多PHPer在進階的時候總會遇到一些問題和瓶頸,業務程式碼寫多了沒有方向感,不知道該從那裡入手去提升,對此我整理了一些資料,包括但不限於:分散式架構、高可擴充套件、高效能、高併發、伺服器效能調優、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql優化、shell指令碼、Docker、微服務、Nginx等多個知識點高階進階乾貨需要的可以免費分享給大家,需要的可以加入我的 PHP技術交流群