PHP getopt Function
Posted on
A few months ago, I read an article in PHP Architect called "The Role of PHP in Ubiquitous Computing" by Jack Polifka. He made the case that PHP is incredibly useful as a language for writing APIs, even if you don't use it for its templating abilities.
What other types of software could PHP be useful for besides traditional websites or APIs? One of the first categories of software that comes to mind is command line applications. PHP is a scripting language, and as such is very well suited for a CLI (command-line interface) environment. However, that got me thinking, how difficult would it be to parse command line arguments in a raw PHP script without any frameworks or libraries?
Parsing command line arguments is very different across scripting languages. In Bash, for example, my experience has been that an unfortunate amount of boilerplate code is required to parse arguments. In PowerShell on the other hand, all you have to do is define the parameters and add a few annotations, and PowerShell does everything else including certain validations.
My research led me to PHP's built-in function for parsing script arguments called getopt
. It is more full-featured than I expected to find, and it takes care of the vast majority of the heavy lifting! I won't get into the weeds about exactly how this function works, you can read the documentation for that. Instead, let's jump right into some examples.
Example 1 - Short Flags
// Command:
// ps -ef
// getopt to parse such arguments:
$arguments = getopt('ef');
// $arguments:
[
'e' => false,
'f' => false
]
Gotcha: When set, a flag argument will have a value of false in the argument array. When not set, the flag argument will be absent from the array.
Example 2 - Long Flags
// Command:
// docker container ls --all
// getopt to parse such arguments:
$arguments = getopt('', ['all']);
// $arguments:
[
'all' => false
]
Example 3 - Short Parameter With Value
// Command:
// tail -n50
// getopt to parse such arguments:
$arguments = getopt('n:');
// $arguments:
[
'n' => '50'
]
Example 4 - Long Parameter With Value
// Command:
// docker image ls --format "table {{.Repository}}:{{.Tag}}\t{{.ID}}\t{{.CreatedSince}}"
// getopt to parse such arguments:
$arguments = getopt('', ['format:']);
// $arguments:
[
'format' => 'table {{.Repository}}:{{.Tag}}\t{{.ID}}\t{{.CreatedSince}}'
]
Example 5 - Multiple Parameter Values
// Command:
// git commit -m "Refactor getCustomer query" -m "This commit improves performance for the getCustomer query by refactoring it to hit the customerCategory index."
// getopt to parse such arguments:
$arguments = getopt('m:');
// $arguments:
[
'm' => [
'Refactor getCustomer query',
'This commit improves performance for the getCustomer query by refactoring it to hit the customerCategory index.'
]
]
This is something else I learned recently. You can pass multiple commit messages to git, and it will add them all to your commit. The first one is meant to be a short summary of what the commit does. In any following messages, you can add as much detail about the commit as you would like.
Example 6 - Optional Value, Specified
// Command:
// git --exec-path="/usr/local/bin/git" status
// getopt to parse such arguments:
$arguments = getopt('', ['exec-path::']);
// $arguments:
[
'exec-path' => '/usr/local/bin/git'
]
Gotcha: Arguments with optional values require the
--param="value"
syntax. If you pass the parameter using the--param value
syntax,getopt
will think that no value was passed and treat everything fromvalue
to the end of the command as positional arguments.
Example 7 - Optional Value, Not Specified
// Command:
// git --exec-path
// getopt to parse such arguments:
$arguments = getopt('', ['exec-path::']);
// $arguments:
[
'exec-path' => false
]
Example 8 - Positional Arguments
// Command:
// rm -rf ./node_modules ./vendor ./dist
// getopt to parse such arguments:
$restIndex = null;
$arguments = getopt('rf', [], $restIndex);
$positionalArguments = array_slice($argv, $restIndex);
// $arguments:
[
'r' => false,
'f' => false
]
// $positionalArguments:
[
'./node_modules',
'./vendor',
'./dist'
]
$argv
is a predefined PHP variable similar to$_SERVER
,$_REQUEST
, or$_GET
.