Subversion Repositories qbpwcf-lib(archive)

Rev

Rev 606 | Rev 666 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

<?php

/*

        QBPWCF, Quick Build PHP website Component base on Fedora Linux.
    Copyright (C) 2015~2024 Min-Jhin,Chen

    This file is part of QBPWCF.

    QBPWCF is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    QBPWCF is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with QBPWCF.  If not, see <http://www.gnu.org/licenses/>.

*/
namespace qbpwcf;

/*
類別說明:
提供多執行序應用的類別.
參考資料:
https://www.php.net/manual/en/book.parallel.php
備註:
建構中
*/
class threads{

        /*
        #函式說明:
        #當前類別被呼叫的靜態方法不存在時,將會執行該函數,回報該方法不存在.
        #回傳結果:
        #$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.
        #$reuslt["error"],執行不正常結束的錯訊息陣列.
        #$result["function"],當前執行的函式名稱.
        #必填參數:
        #$method,物件,為物件實體或類別名稱,會自動置入該參數.
        #$arguments,陣列,為呼叫方法時所用的參數.
        #可省略參數:
        #無.
        #參考資料:
        #__call=>http://php.net/manual/en/language.oop5.overloading.php#object.callstatic
        #備註:
        #無.
        */
        public function __call($method,$arguments){

                #取得當前執行的函式
                $result["function"]=__FUNCTION__;

                #設置執行不正常
                $result["status"]="false";

                #設置執行錯誤
                $result["error"][]=__NAMESPACE__ ."/".$method."() 不存在!";

                #設置所丟入的參數
                $result["error"][]=$arguments;

                #回傳結果
                return $result;

                }#function __call end

        /*
        #函式說明:
        #當前類別被呼叫的靜態方法不存在時,將會執行該函數,回報該方法不存在.
        #回傳結果:
        #$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.
        #$reuslt["error"],執行不正常結束的錯訊息陣列.
        #$result["function"],當前執行的函式名稱.
        #必填參數:
        #$method,物件,為物件實體或類別名稱,會自動置入該參數.
        #$arguments,陣列,為呼叫方法時所用的參數.
        #可省略參數:
        #無.
        #參考資料:
        #__call=>http://php.net/manual/en/language.oop5.overloading.php#object.callstatic
        #備註:
        #無.
        */
        public static function __callStatic($method,$arguments){

                #取得當前執行的函式
                $result["function"]=__FUNCTION__;

                #設置執行不正常
                $result["status"]="false";

                #設置執行錯誤
                $result["error"][]="欲呼叫的". __NAMESPACE__ ."/".$method."() 不存在!";

                #設置所丟入的參數
                $result["error"][]=$arguments;

                #回傳結果
                return $result;

                }#function __callStatic end

        /*
        #函式說明:
        #展示多執行序運作.
        #回傳結果:
        #$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.
        #$reuslt["error"],執行不正常結束的錯訊息陣列.
        #$result["function"],當前執行的函式名稱.
        #必填參數:
        #無.
        #可省略參數:
        #無.
        #參考資料:
        #無.
        #備註:
        #無.
        改用 proc 試試 https://www.php.net/manual/en/function.proc-open.php
        */
        public static function demo(){
        
                #執行demo
                var_dump(self::proc_demo());
        
                }#function demo end

        /*
        #函式說明:
        #透過proc展示多執行序運作.
        #回傳結果:
        #$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.
        #$reuslt["error"],執行不正常結束的錯訊息陣列.
        #$result["function"],當前執行的函式名稱.
        #必填參數:
        #無.
        #可省略參數:
        #無.
        #參考資料:
        #https://www.php.net/manual/en/function.proc-open.php
        #備註:
        #無.
        */
        public static function proc_demo(){
        
                #初始化 descriptorspec
                $descriptorspec = array();
                
                #stdin is a pipe that the child will read from
                $descriptorspec[]=array("pipe", "r");
                
                #stdout is a pipe that the child will write to
                $descriptorspec[]=array("pipe", "w");
                
                #stderr is a pipe that the child will write to
                $descriptorspec[]=array("pipe", "w");
                
                #The initial working dir for the command. This must be an absolute directory path, or null if you want to use the default value (the working dir of the current PHP process) 
                $cwd = null;
                
                #An array with the environment variables for the command that will be run, or null to use the same environment as the current PHP process 
                $env = array("QBPWCF" => "Quick Build PHP Website Componment base on Fedora Linux");
                
                #初始化儲存要多執行序執行的程式
                $codes=array();
                
                #初始化要demo用的url
                $demoUrl="https://qbpwc.sourceforge.io/";
                
                #要多執行序執行的程式1
                $codes[]=array("bash","curl -v -L --ssl-reqd ".$demoUrl);
                
                #要多執行序執行的程式2
                $codes[]=array("bash","curl -v -L --ssl-reqd ".$demoUrl);
                
                #要多執行序執行的程式3
                $codes[]=array("bash","curl -v -L --ssl-reqd ".$demoUrl);
                
                #debug
                #var_dump(__LINE__,$codes);
                
                #儲存每個要執行的程式資訊
                $process=array();
                
                #針對每個要執行的程式內容
                foreach($codes as $index=>$code){
                
                        #取得要用什麼程式執行
                        $executeBy=$code[0];
                
                        #取得要執行的程式內容
                        $code=$code[1];
                        
                        #運行 php 程式,並儲存 resource
                        $process[$index]["resource"] = proc_open($executeBy, $descriptorspec, $pipes, $cwd, $env);
                        
                        #儲存對應的 pipes
                        $process[$index]["pipes"]=$pipes;
                        
                        #debug
                        #var_dump(__LINE__,$process[$index]);
                        
                        #如果有成功執行
                        if(is_resource($process[$index]["resource"])){
                        
                                #$pipes now looks like this:
                                #0 => writeable handle connected to child stdin
                                #1 => readable handle connected to child stdout
                                #2 => readable handle connected to child stdin
                                
                                #寫入內容作為 $executeBy 的輸入
                                $bytes2write=fwrite($process[$index]["pipes"][0], $code);
                                
                                #debug
                                #var_dump(__LINE__,$bytes2write);
                                
                                #結束輸入
                                fclose($process[$index]["pipes"][0]);
                        
                                }#if end
                                
                        #反之,代表運行 php 失敗
                        else{
                        
                                #初始化暫存執行結果的變數
                                $cmdRes=array();
                                
                                #設置執行失敗
                                $cmdRes["status"]="false";
                                
                                #設置執行錯誤訊息
                                $cmdRes["error"]="execute program by \"".$executeBy."\" failed!";
                                
                                #設置執行結果
                                $result["content"][]=$cmdRes;
                                
                                }#else end
                
                        }#foreach end
                
                #debug
                #var_dump(__LINE__,$process);
                
                #針對每個回饋
                foreach($process as $index => $ps){
                
                        #取得 proc resource
                        $resource=$ps["resource"];
                
                        #取得標準輸出
                        $stdout=stream_get_contents($process[$index]["pipes"][1]);
                
                        #取得錯誤輸出
                        $stderr=stream_get_contents($process[$index]["pipes"][2]);
                
                        #debug
                        #var_dump($stdout);
                
                        #初始化暫存執行狀況的變數
                        $cmdRes=array();
                        
                        #設置執行失敗訊息
                        $cmdRes["error"]=$stderr;
                        
                        #設置執行結果
                        $cmdRes["content"]=$stdout;
                        
                        #debug
                        #var_dump($cmdRes);
                        
                        #結束讀取標準輸出
                        fclose($process[$index]["pipes"][1]);
                        
                        #結束讀取錯誤輸出
                        fclose($process[$index]["pipes"][2]);
                        
                        #It is important that you close any pipes before calling proc_close in order to avoid a deadlock
                        $cmdRes["statusCode"] = proc_close($resource);
                        
                        #debug
                        #var_dump($cmdRes["statusCode"]);
                        
                        #預設執行不正常
                        $cmdRes["status"]="false";
                        
                        #如果執行正常
                        if($cmdRes["statusCode"]===0){
                        
                                #設置執行正常
                                $cmdRes["status"]="true";
                        
                                }#if end
                        
                        #保存結果
                        $result["content"][]=$cmdRes;
                
                        #debug
                        #var_dump($result);
                
                        }#foreach end
                        
                #設置執行正常
                $result["status"]="true";
                
                #debug
                #var_dump($result);
                
                #回傳結果
                return $result;
                
                }#function proc_demo end

        /*
        #函式說明:
        #透過parallel展示多執行序運作.
        #回傳結果:
        #$result["status"],執行是否正常,"true"代表正常,"false"代表不正常.
        #$reuslt["error"],執行不正常結束的錯訊息陣列.
        #$result["function"],當前執行的函式名稱.
        #必填參數:
        #無.
        #可省略參數:
        #無.
        #參考資料:
        #https://www.php.net/manual/en/class.parallel-runtime.php
        #備註:
        #需要於編譯PHP時啟用該套件   
        */
        public static function parallel_demo(){
        
                #初始化要回傳的結果
                $result=array();

                #取得當前執行的函數名稱
                $result["function"]=__FUNCTION__;
        
                #新增程序r1
                $r1=new \parallel\Runtime();
        
                #r1要執行的函式
                $thread_r1_function=function($conf){
                
                        #提示開始
                        echo $conf["id"]." start".PHP_EOL;
                
                        #跑 $conf["i"] 次
                        for($i=0;$i<$conf["i"];$i++){
                        
                                #題書$i數值
                                echo "\$i=".$i.PHP_EOL;
                        
                                }#for end
                
                        #提示結束
                        echo $conf["id"]." end".PHP_EOL;
                
                        };#function end

                #r1的參數
                $args_r1=array();
                $args_r1["id"]="r1";
                $args_r1["i"]=10;

                #運行程序r1
                #程序函式為 $thread_r1_function
                #參數陣列為 $args_r1
                $future_r1=$r1->run($thread_r1_function, $args_r1);
        
                #新增程序r2
                $r2=new \parallel\Runtime();
        
                #r2要執行的函式
                $thread_r2_function=function($conf){
                
                        #提示開始
                        echo $conf["id"]." start".PHP_EOL;
                
                        #跑 $conf["i"] 次
                        for($i=$conf["i"];$i>0;$i--){
                        
                                #題書$i數值
                                echo "\$i=".$i.PHP_EOL;
                        
                                }#for end
                
                        #提示結束
                        echo $conf["id"]." end".PHP_EOL;
                
                        };#function end

                #r2的參數
                $args_r2=array();
                $args_r2["id"]="r2";
                $args_r2["i"]=10;
        
                #運行程序r2
                #程序函式為 $thread__r2_function
                #參數陣列為 $args_r2
                $future_r2=$r2->run($thread_r2_function, $args_r2);
                
                #存放有多少在執行的程序
                $futureArray=array();
                $futureArray[]=$future_r1;
                $futureArray[]=$future_r2;
                
                #當有程序尚未結束時
                while(!empty($futureArray)){
                
                        #針對每個 Future
                        foreach($futureArray as $index => $Future){
                        
                                #如果執行完成了
                                if($Future->done()){
                                
                                        #移除之
                                        unset($futureArray[$index]);
                                
                                        }#if end
                        
                                }#foreach end
                
                        }#while end
                
                #提示所有程序都執行結束了
                echo "all done!".PHP_EOL;
                
                #設置執行正常
                $result["status"]="true";
                
                #回傳結果
                return $result;
                
                }#function parallel_demo end

        }#class threads end