許多 php 套件如 Symfony Console 或 Joomla CLI Application 接已經幫我們封裝好方便的 CLI 介面可以直接使用,這裡來聊聊如果不使用 Framework ,該如何自行操作 PHP IO Stream 來輸入與輸出內容到命令列上面。
安裝 PHP CLI 套件
某些 Linux 的 LAMP 包預設沒有安裝 CLI 模組,可以自行安裝,以 Ubuntu 為例:
apt-get install php5-cli
Windows 可參考: 設定環境變數讓 Windows 命令列可以執行 php 指令
簡單的 PHP 命令列程式
假設我們先寫一個 hello.php 檔案,內容如下:
<?php
echo "Hello World";
接著在命令列執行
$ php hello.php
就會出現
Hello World
非常的簡單。
輸入與輸出資料
PHP 的封裝協定
PHP 提供了一組封裝協定幫助我們存取不同的環境介面,例如 phar://
可存取 .phar 檔內的資料,file://
用來存取本地端文件系統,詳情可以參考 PHP 官網介紹。
而我們要用的是 php://
這個協定,它包含了幾個常用的封裝資料:
php://input
: 執行時輸入的參數資料,類似$_REQUEST
的功能。php://stdout
: 執行過程由程式本身輸出到設備上的資料。php://stdin
: 執行過程中要求用戶輸入進來的資料。php://stderr
: 丟出錯誤訊息。
這些封裝資料都是 Resource 的形式,就如同檔案系統一般,我們需要使用 file 函數來存取。
Stdout 標準輸出
假設我們想要輸出資料到命令列上,最簡單的方法當然是直接 echo
,當然充滿 Geek 之驕傲的工程師們可不能這樣做,我們來使用標準輸出印出文字吧:
<?php
$fp = fopen('php://stdout', 'w');
fwrite($fp, "Hello World!!!\n");
fclose($fp);
讓我們執行看看這個檔案,應該會出現:
$ php hello.php
> Hello World!!!
$
也就是說,我們只要把 php://stdout
當作檔案操作寫入即可,stdout
是一個 IO Stream ,可以在我們寫入資料時動態反映,因此命令列執行過程會主動輸出寫入的資料到設備上。
Stdin 標準輸入
如果我們想要輸入資料,則必須用 fread
讀取 php://stdin
:
<?php
$fh = fopen('php://stdin', 'r');
echo "Please type your name: ";
$str = fread($fh, 1000);
echo "Your name is: ".$str;
fclose($fh);
輸出結果:
$ php hello.php
> Please type your name:
讓我們輸入點字串
$ php hello.php
> Please type your name: Asika
> Your name is: Asika
$
當出現: Please type your name:
的當下,程式會暫停執行直到你輸入資料為止。
以下程式碼可以無止盡的要求你輸入資料(笑):
<?php
$fh = fopen('php://stdin', 'r');
echo "Type something: ";
while($str = fread($fh,1000)){
echo "You type: " . $str;
echo "Type something: ";
}
Stderr 標準錯誤
標準錯誤與標準輸出有點像:
<?php
try
{
throw new RuntimeException('Standard Error');
}
catch(RuntimeException $e)
{
$fh = fopen('php://stderr', 'w');
fwrite($fh, $e->getMessage() . "\n");
fclose($fh);
}
直接輸出資料到設備上,不一定要用 Exception ,那只是範例而已。
使用 STD 常數
這三個封裝協定各自有一個代表的常數,分別是: STDIN
, STDOUT
, STDERR
。
以 STDOUT
來說,它代表著指向 php://stdout
的 Resource ,意味著我們連 fopen
都不需要了,直接對它寫入即可,例如原本是這樣:
<?php
$fp = fopen('php://stdout', 'w');
fwrite($fp, "Hello World!!!\n");
fclose($fp);
可以改寫成這樣:
<?php
fwrite(STDOUT, "Hello World!!!\n");
輸入資料更簡單:
echo fgets(STDIN);
非常方便,還不需要 fclose。
接收參數
可接收的參數有兩種,分別是 $argv
與 $argc
:
$argv
等同於 $_SERVER['argv']
,兩者內容一樣,可以取得所有輸入的參數資料,例如我 php 這樣寫:
<?php
print_r($argv);
// OR
print_r($_SERVER['argv']);
接著輸入
$ php hello.php arg subarg -a -b -cd -n name --help --long-param
就會輸出
Array
(
[0] => hello.php
[1] => arg
[2] => subarg
[3] => -a
[4] => -b
[5] => -cd
[6] => -n
[7] => name
[8] => --help
[9] => --long-param
)
有些 Framework 會額外幫我們把參數處理成 Key Value 的形式,例如下面這樣:
Array
(
[args] => Array
(
[0] => arg
[1] => subarg
)
[params] => Array
(
[a] => 1
[b] => 1
[c] => 1
[d] => 1
[n] => name
[help] => 1
[long-param] => 1
)
)
$argc
$argc
等同 $_SERVEER['argc']
,只會返回參數數量而已。
其他的一些 php cli 可用參數
大概就先介紹到這裡,應該已經可以寫簡單的應用了,其他還有一些 php 本身好用的參數可用:
-a
直譯模式,可以一行一行輸入程式碼最後再輸出。參考這裡-v
輸出 php 版本訊息。-r
直接用一個字串來執行,例如php -r "echo 'hello';"
-i
輸出 phpinfo ,等同php -r "phpinfo();"
-h
說明
更多說明請參見 php 官方文件