The command-shell.php program shown in Example 20-1 provides a shell-like prompt to let you execute PHP code interactively. It reads in lines using readline( ) and then runs them with eval( ). By default, it runs each line after it's typed in. In multiline mode (specified with -m or --multiline), however, it keeps reading lines until you enter . on a line by itself; it then runs the accumulated code.
Additionally, command-shell.php uses the Readline word-completion features to more easily enter PHP functions. Enter a few characters and hit Tab to see a list of functions that match the characters you've typed.
This program is helpful for running snippets of code interactively or testing different commands. The variables, functions, and classes defined in each line of code stay defined until you quit the program, so you can test different database queries, for example:
% php -q command-shell.php
[1]> require 'DB.php';
[2]> $dbh = DB::connect('mysql://user:pwd@localhost/phpc');
[3]> print_r($dbh->getAssoc('SELECT sign,planet,start_day FROM zodiac WHERE element
LIKE "water"'));
Array
(
[Cancer] => Array
(
[0] => Moon
[1] => 22
)
[Scorpio] => Array
(
[0] => Mars
[1] => 24
)
[Pisces] => Array
(
[0] => Neptune
[1] => 19
)
)
The code for command-shell.php is in Example 20-1.
// Load the readline library
if (! function_exists('readline')) {
dl('readline.'. (((strtoupper(substr(PHP_OS,0,3))) == 'WIN')?'dll':'so'))
or die("Readline library required\n");
}
// Load the Console_Getopt class
require 'Console/Getopt.php';
$o = new Console_Getopt;
$opts = $o->getopt($o->readPHPArgv(),'hm',array('help','multiline'));
// Quit with a usage message if the arguments are bad
if (PEAR::isError($opts)) {
print $opts->getMessage();
print "\n";
usage();
}
// default is to evaluate each command as it's entered
$multiline = false;
foreach ($opts[0] as $opt) {
// remove any leading -s
$opt[0] = preg_replace('/^-+/','',$opt[0]);
// check the first character of the argument
switch($opt[0][0]) {
case 'h':
// display help
usage();
break;
case 'm':
$multiline = true;
break;
}
}
// set up error display
ini_set('display_errors',false);
ini_set('log_errors',true);
// build readline completion table
$functions = get_defined_functions();
foreach ($functions['internal'] as $k => $v) {
$functions['internal'][$k] = "$v(";
}
function function_list($line) {
return $GLOBALS['functions']['internal'];
}
readline_completion_function('function_list');
$cmd = '';
$cmd_count = 1;
while (true) {
// get a line of input from the user
$s = readline("[$cmd_count]> ");
// add it to the command history
readline_add_history($s);
// if we're in multiline mode:
if ($multiline) {
// if just a "." has been entered
if ('.' == rtrim($s)) {
// eval() the code
eval($cmd);
// clear out the accumulated code
$cmd = '';
// increment the command count
$cmd_count++;
// start the next prompt on a new line
print "\n";
} else {
/* otherwise, add the new line to the accumulated code
tacking on a newline prevents //-style comments from
commenting out the rest of the lines entered
*/
$cmd .= $s."\n";;
}
} else {
// if we're not in multiline mode, eval() the line
eval($s);
// increment the command count
$cmd_count++;
// start the next prompt in a new line
print "\n";
}
}
// display helpful usage information
function usage() {
$my_name = $_SERVER['argv'][0];
print<<<_USAGE_
Usage: $my_name [-h|--help] [-m|--multiline]
-h, --help: display this help
-m, --multiline: execute accumulated code when "." is entered
by itself on a line. The default is to execute
each line after it is entered.
_USAGE_;
exit(-1);
}
Copyright © 2003 O'Reilly & Associates. All rights reserved.