1. 程式人生 > >PHP Yii 命令列程式以及定時任務詳解

PHP Yii 命令列程式以及定時任務詳解

為啥要編寫命令列程式?

命令列程式通常是一個指令碼,但是PHP Yii 是web開發語言,如何能開發指令碼程式?

所以,首先我們要明白使用PHP Yii 編寫指令碼語言的目的和原理。

  • 目的

設想這麼一個場景,你開發了一個電子商務網站,在測試階段,你希望模擬使用者的下單操作。或者你開發了一個類股票網站,在測試階段,你需要模擬使用者的委託買入、賣出操作,並撮合使用者的買入和賣出。畢竟,如果想模擬大量使用者的操作,而通過手動在資料庫中新增測試資料,這工作量有點大。

所以,編寫Yii 指令碼的目的是,通過執行指令碼,自動生成使用者的下單操作。這個類似於一個伺服器端的程式,可以用JAVA寫,但是我們是PHP程式設計師啊,當然用PHP實現了。

  • 原理和流程
使用PHP Yii 編寫指令碼的程式的基本原理是這樣的:

(1)編寫一個Command類,類名和檔名以Command為字尾,同時繼承父類CConsoleCommand,檔案存放在工程下的protected/commands/目錄下,例如:

<span style="font-family:Tahoma;font-size:12px;">class TestCommand extends CConsoleCommand</span>

(2)編寫Command類的動作,類似控制器的動作,動作名需要以action為字首,例如:

<span style="font-family:Tahoma;font-size:12px;">public function actionTest(){
 	echo "command test successfully.";
 }</span>

echo的內容會列印在Windows DOS或Linux的命令列程式頁面上。完整的命令類如下:

<span style="font-family:Tahoma;font-size:12px;"><?php
class FarmProduceMatchCommand extends CConsoleCommand
{

 /**
  * Execute the action.
  * @param array command line parameters specific for this command
  */</span>
<span style="font-family:Tahoma;font-size:12px;">/*
public function run($args)
{
if(!isset($args[0]))
$this->usageError('please input params.');
echo('you input :\n');
var_dump($args);
}
*/
 public function actionTest(){
 	echo "command test successfully.";
 }
}</span>

(3)如何執行自定義的Command類和動作呢,很簡單,不需要配置PHP和Yii的環境和變數。開啟Dos(windows系統)或Terminal(Linux系統),在命令列,將目錄定位到你的yii工程的protected目錄,該目錄下有yiic命令程式。比如,我的工程目錄在“C:\xampp\htdocs\syjjq2”,“syjjq2”就是我的yii工程。在命令列將目錄定位到syjjq2工程下的protected目錄,工程目錄結構如下:

為什麼要呼叫你工程下的protected目錄的yiic.bat,而不直接呼叫Yii框架目錄下的yiic.bat,主要原因是你的工程下的protected下的yiic.bat能自動識別該工程中的命令類和動作。而yii框架目錄下的則找不到你自定義的命令。

下面我們操作一下在命令列呼叫自定義的動作,命令格式是:【yiic 自定義命令類名稱 動作名稱】。需要注意的是,這裡的命令類名稱和動作名稱,與控制器名稱和動作名稱一樣,可以把命令類想象成一個控制器,所以,命令名就是命令類的類名去掉command字尾,然後第一個字母小寫,動作名稱就是動作函式的名稱去掉action字首,然後第一個字母小寫即可。比如,我想看看我自定義的FarmProduceMatchCommand命令類有幾個動作,可以使用【yiic 自定義命令類名稱】:

其實這種命令寫法,沒有指定要執行該命令類的哪一個動作,預設會執行名稱為index的動作,但是,我們這個類沒有名為index 的動作,所以它報了一個錯,同時,會把該命令類下所有的動作都羅列出來。

好了,那我們正式執行我們自定義的FarmProduceMatchCommand命令類的test動作:

到此,我們自定義的命令類和動作就執行成功了!

  • 進階

(1)run函式。

Command類的起始函式為run,該函式繼承自CConsoleCommand類,當你自定義的Command類過載run函式的時候,其他的自定義動作對於命令列來說都會失去效果,即當run函式存在的時候,無法在命令列呼叫其他的自定義動作,因為run函式會攔截其他動作的呼叫,把呼叫的動作認為是run函式的傳入引數。比如,我們把上面的FarmProduceMatchCommand類中的run函式部分的註釋去掉,你再在命令列執行剛才的【yiic farmProduceMatch test】命令試試,執行結果如下:

看到沒,你希望執行的是farmProduceMatch的test動作,結果執行的是run函式,並且,你輸入的動作名test被認為是run函式的一個傳入引數。

run函式接收一個引數陣列,你可以在命令列輸入多個引數,以空格隔開即可,如:

yiic farmProduceMatch param1  param2  param3  param4……

也就是說,如果你的命令類中只有一件事情要處理,可以直接在run函式中編寫。但通常來說,業務比較複雜的情況下,就需要在一個命令類中執行多個動作了,比如:生成委託買入訂單動作,生成委託賣出訂單動作,生成撮合委託訂單動作……當你需要編寫多個動作,並且分別需要在命令列中呼叫某個動作的時候,就需要把這個run函式給註釋掉了。

(2)動作函式如何在命令列傳入引數。

我們把上面的test動作稍微改一下:

<span style="font-family:Tahoma;font-size:12px;">public function actionTest($param1, $param2){
 	echo "command test successfully. you have input:$param1, $param2";
 }</span>

我給test函式添加了兩個引數,並在螢幕上打印出來使用者輸入的兩個引數:


在命令列傳入引數的時候要遵循格式【yiic 自定義命令類名稱 動作名稱 --引數1=引數值 --引數2=引數值 --引數3=引數值……】。

即要在你的動作引數名錢加兩個‘-’,後面跟上賦值即可。多個引數賦值使用逗號隔開即可。

(3)執行yiic時報錯。

執行yiic命令時,如果報錯的話,例如php不是內部或外部命令之類的,你需要修改一下protected/yiic.bat檔案,原始內容如下:

<span style="font-family:Tahoma;font-size:12px;">@echo off

rem -------------------------------------------------------------
rem  Yii command line script for Windows.
rem  This is the bootstrap script for running yiic on Windows.
rem -------------------------------------------------------------

@setlocal

set BIN_PATH=%~dp0

if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe

"%PHP_COMMAND%" "%BIN_PATH%yiic.php" %*

@endlocal</span>

你要把“PHP_COMMAND=php.exe”改成你實際的PHP路徑。比如我用的是整合PHP環境xampp,放在C:目錄下的,那麼php目錄在“C:\xampp\php”。改成“PHP_COMMAND=C:\xampp\php\php.exe”即可。

(4)使用yiic命令,找不到自定義的命令類和動作。

其實這個很簡單,前面我已經提到過了。自定義的command類,要放在/protected/commands/目錄下;執行的yiic命令為/protected/yiic.bat檔案,不要執行Yii framework下的yiic;檢查自定義command類的檔名稱和類名稱命名是否規範,以及動作的命名是否規範。

(5)如何配置command類的相關配置項

Yii框架分為兩個部分,一個是web,一個是cli,即命令列程式。cli模式有單獨的配置檔案:“/protected/config/console.php”。比如,你的自定義command類中,需要呼叫資料庫,模型類,或者其他模組的檔案,就需要在console.php中配置了。配置方法和main.php中一樣。

  • 高階
上面的例子我們已經講了,如何編寫命令類和動作,如何執行,等等。到此,我們也大概瞭解了yii的命令列執行機制,其實就是通過yiic命令呼叫某個命令類和動作。

下面,我們設想如下情景,我們需要模擬不同的使用者在不同的時間進行下單操作。如果只是產生一條測試資料的話,我們直接在命令列中執行一下該動作即可,但是模擬不同時間不同使用者的情況的話,我們就需要定時執行某個動作了。

定時執行某個動作,我們可以不用cli,直接寫個控制器,然後寫個動作,動作中有個死迴圈,每隔多長時間執行一次某個函式來生成一條測試資料。

但這種方法我覺得太過於笨重了,畢竟php屬於web語言,讓他執行一個服務端程式的事情確實有些不妥。

如果瞭解windows指令碼或linux shell的同學應該可以想到這種方法,把命令列執行自定義命令類和動作的指令寫入一個文字檔案,然後將檔名的字尾改成*.bat(Windows系統),這樣我們就建立了一個指令碼,雙擊執行這個指令碼,就會自動執行生成一條模擬使用者下單的測試資料,就不用我們在命令列輸入命令了。

比如,我建立一個test.bat檔案,使用記事本開啟,輸入以下內容:

C:\xampp\htdocs\syjjq2\protected\yiic farmProduceMatch test --param1=hello --param2=world

輸入好後儲存,我們就建立好了這個指令碼。

如何自動執行這個指令碼呢?我們可以建立一個系統計劃任務,定時執行這個指令碼。以下以Win7為例,講解如何建立定時計劃任務來定時執行我們的指令碼。

首先,右鍵“計算機”,選擇“管理”選單,進入“計算機管理”頁面:


在左欄,選擇“計劃任務程式”,然後在右欄選擇“建立任務…”,開啟建立任務對話方塊。

(1)建立任務-常規

任務的名稱和描述可以隨意寫。安全選項和配置根據自己的需求寫。其中,安全選項如果選擇“只在使用者登入時執行”,如果你的電腦又沒設定密碼,不需要登入,你的定時任務就永遠無法執行了,所以,我選擇第二個。

(2)建立任務-觸發器

開啟“觸發器”選項卡,點選“新建…”按鈕,我們新建一個觸發器。觸發器的內容可以根據你的需求填寫,上圖中,我建立了一個從當前時間開始每隔5分鐘執行一次指令碼的觸發器。“啟用”一定要勾上啊。

3)建立任務-操作

開啟“操作”選項卡,點選“新建…”按鈕,新建一個操作。操作型別為“啟動程式”,然後選擇要執行的指令碼檔案的位置。如果要新增起始引數的話,可以在該頁面進行配置。

4)建立任務-條件

開啟“條件”選項卡,根據自己的需求選擇。

4)建立任務-設定

開啟“設定”選項卡,根據個人需求進行配置。

然後就可以點選“確定”按鈕儲存該任務計劃了。

到此,任務計劃已經建立完成,但是還沒有結束。點選確定按鈕建立任務計劃成功後,在任務計劃頁面我們會看到我們建立的任務:

可以看到,我們建立的任務已經在任務列表中了,但是“狀態”是“準備就緒”,也就是說任務還沒開始執行。選擇我們建立的任務,在右欄中選擇“執行”,再看看我們建立的任務狀態,變成“正在執行”就說明我們已經建立並執行任務計劃成功了!