getopt-php / getopt-php Goto Github PK
View Code? Open in Web Editor NEWA PHP library for command-line argument processing
Home Page: http://getopt-php.github.io/getopt-php/
License: MIT License
A PHP library for command-line argument processing
Home Page: http://getopt-php.github.io/getopt-php/
License: MIT License
If I parse command line options and one of the options haven't been defined in Getopt (by doing addOption), there's an error because of the undefined option. I'd like to use Getopt in some code where the expected command-line options are defined dynamically and not always known up front. It would be great to have an option that allows for extra options on the command-line that haven't been defined. Such an option could be passed in when instantiating the Getopt object.
When adding a required operand to a command it is impossible to get help for the command because of the error:
Operand NAME is required.
i.e:
$getopt->addOption('h','help');
$cmd = new MyCommand();
$getopt->addCommand( $cmd);
// In class MyCommand:
class MyCommand extends Command
{
public function __construct() {
parent::__construct('command',[ $this, 'handle'] );
$this->addOperand('op1',Operand::REQUIRED);
}
}
to reproduce:
./myapp command --help
In HEAD composer.json contains a psr-0 autoload reference that is needed to the package to work when installing in composer. However, the only tagged version: 1.0.0 does not have this entry in composer.json.
Could you please tag the current HEAD as 1.0.1 or similar?
I find the page at http://getopt-php.github.io/getopt-php/help.html a bit confusing, it's not really clear just reading that and without looking at the code, to understand what has to be done, and how one is supposed to customize things.
I am not sure which is the POSIX standard:
command operand --help
: --help parsed as option
It would be good if the above example could work.
It is not that hard to implement it, however the CommandLineParser
must loop through all the provided options. I can send a PR for it.
But I would like to know whether not supporting this is a decision made or just implemented this way.
For version 3.2 we added translations for errors with the new translator. Describe how they can customize the translations and change the language now and how to use the translation service for custom messages.
In version 3.2 we also added custom validation messages and callbacks to retrieve the custom validation message. This has to be described as well.
Getopt-php syntax can be improved for some real world cases. It can be be more flexible and provide a bit of syntactic sugar to their users.
$operands = $opt->getOptions();
if (empty($operands)) {
$opt->showHelp();
exit;
}
...
//can be with \Countable
if (count($opt) == 0) {
$opt->showHelp();
exit;
}
$queueCount = $opt->getOption('q');
//can be with \ArrayAccess
$queueCount = $opt['q'];
foreach ($opt->getOptions() as $k => $v) {
...
}
//can be with \IteratorAggregate or \Traversable
foreach ($opt as $k => $v) {
...
}
Currently GetOpt::getOperand('operand')
throws. This is problematic when you use commands and don't know if the operand is given or not. Like GetOpt::getOption('option')
it should return null
when the option does not exist.
Hi.
I don't know if there'is a bug, or a concept of library.
When run a comand line of my app, with a option without value I get a exception instead a help message.
command.php --type value #ok
command.php #any value show help of getOpt
command.php --type #error
PHP Fatal error: Uncaught exception 'UnexpectedValueException' with message 'Option 'type' must have a value' in /Volumes/iDatos/abkrim/ownCloudTDC/tamainut/desarrollo/cprsync/vendor/ulrichsg/getopt-php/src/Ulrichsg/Getopt/CommandLineParser.php:155
my code
$getopt = new Getopt(array(
(new Option('t', 'type',Getopt::REQUIRED_ARGUMENT))
->setDescription('full|acct Type backup full->all accounts acct only account'),
(new Option('u', 'user', Getopt::REQUIRED_ARGUMENT))
->setDescription('Put user account for backup'),
new Option(null, 'help'),
new Option(null, 'version')
));
try {
$getopt->parse(); //<<<< BREAK HERE
if ($getopt['version']) {
echo "cprsyncbackup.php vAlfa\n";
exit(0);
}
if ($getopt['help']) {
echo $getopt->getHelpText();
exit(0);
}
if (($getopt['type'] != 'acct') && ($getopt['type'] != 'full')) {
echo "Hola\n";
//exit(0);
echo $getopt->getHelpText();
exit(0);
}
// Here future code for verify user on value "user"
/*
* @todo verify user
*/
// error handling and --help functionalitie
} catch (UnexpectedValueException $e) {
echo "Error: " . $e->getMessage() . "\n";
echo $getopt->getHelpText();
exit(1);
}
return $getopt;
Best regards
Traditional getopt
usage (across most languages, not just PHP's native implementation) doesn't require a space between short arguments and their values. This library does, which is inconsistent with expected behavior.
Expected/traditional behavior:
$ php ngo.php -a -bb -c
Array
(
[a] =>
[b] => b
[c] =>
)
$ cat ngo.php
<?php
print_r(getopt('ab:c::'));
Actual result:
$ php go.php -a -bb -c
Option 'b' must have a value
$ cat go.php
<?php
require_once 'vendor/autoload.php';
$g = new Ulrichsg\Getopt\Getopt('ab:c::');
try {
$g->parse();
print_r($g->getOptions());
} catch (\Exception $e) {
echo $e->getMessage();
exit(1);
}
(I'll take a stab at a PR to fix this as well)
snippet from a psy shell:
>>> GetOpt\Operand::create('test', GetOpt\Operand::MULTIPLE)->getValue()
=> null
>>> GetOpt\Option::create('t', 'test', GetOpt\GetOpt::MULTIPLE_ARGUMENT)->getValue()
=> []
I would say it is a bug but maybe someone has a different meaning?
Sorry for creating an issue for this, but I can't see any reference to positional arguments in the documentation. Positional arguments are those without a leading dash (-
), which are identified by the position, or order, in which they appear rather than by name. Are positional arguments supported by some mechanism?
With the latest influx of features, and the continuing interest in further development, the current code structure does not cut it anymore. As of v1.3.0, the Getopt.php file measures 560 lines, its longest method (parse()) alone is over 80 lines long - not counting the docblock. It needs to be split up into more manageable units.
Currently the message is always 'Option \'%s\' has an invalid value'
. It would be helpful to have more descriptive messages. You can have this already in custom validation functions, but it's not possible for php functions. The proposal was to pass a second variable for validation.
Example for custom validation:
$option = Option::create('u', 'user')
->setValidation(function ($value) {
if (!DI::em()->fetch('User', $value)) {
throw new Invalid(sprintf('User %s not found', $value));
}
return true;
});
Example using php functions (new feature):
$option = Option::create('a', 'alpha')
->setValidation('is_numeric', 'Alpha has to be numeric');
I have an app read line text from client
I want to parse option from line input but there has no package can do this
Hey,
I would love to have an option where parameters would be aggregated.
For example:
php script.php --client blub --domain foo.bar --domain example.com
Getting the parameter domain
then would result in an array containing both domain values.
domain
should be defined to be a multi value parameter, of course.
This project can do something like that - just for orientation.
I know some years ago php 5.3 was alive but even the latest debian stable has now php 7 and I'm wondering if we still need php 5.3 support.
php 5.3 is not supported by zend since almost 3 years. it's not only about short array syntax and using $this in a closure. there is also no callable
type for parameters.
the nicest would be to ask everyone who is using this lib but I don't see a way for this. from packagist statistics it looks like 5.3 is still supported by a lot of packages but almost no one is using it:
https://seld.be/notes/php-versions-stats-2017-1-edition
@ulrichsg what do you think?
It is very necessary thing. This is syntactic sugar, but allows you to write less the same type of code. The simplest example:
$getopt = new Getopt(array(
array('t', 'threads', Getopt::OPTIONAL_ARGUMENT, 'Specify calculation max theread count')
));
.....
$threads = $getopt->getOption('t') ?: 1;
//more elegant way
$getopt = new Getopt(array(
array('t', 'threads', Getopt::OPTIONAL_ARGUMENT, 'Specify calculation max theread count', 1)
));
$threads = $getopt->getOption('t');
There is no point in having them if they are not used...
The count method should return the count of options given in the command line. But it actually gives the count of options with short and long name. This differs also from the count of the ArrayIterator
.
To reproduce:
$getopt = new Getopt([
new Option('a', 'alpha'),
new Option('b', 'beta'),
]);
$getopt->parse('-ab');
$count = $getopt->count(); // this should be 2 but it is 4
$iterator = $getopt->getIterator();
var_dump($count === $iterator->count());
I am currently working on a console application and it works like the following:
Getopt
class.help
or version
option is passed.My problem is that if a command defines some options then it simply fails because when parse is called they are not defined yet. I saw some PRs/issues for explicit options. Will it solve it solve my problem?
Also, I am curious if there are any way to remove operands (the command name) from the object. It seems that $operand
is private so I hardly see a solution by extending the class.
First of all, thanks for this great open source library!
The current refactorings for the new version look promising and were really needed,
however I have some additional ideas:
Tell me what you think.
I have already implemented the first two and have made a pull request.
If you like (some of) these ideas, I will definitely contribute more in the near future.
I noticed there are several feature branches in the repo that have been merged to master, is there any particular reason for keeping them in ? If not, I would suggest deleting them
$ git branch --remote --merged master |grep -Ev "master|HEAD"
origin/2.x
origin/fix-iterator
origin/fix-requiredOperands
origin/fix-unknownOperands
origin/getters
origin/oop-help
origin/update-documentation
Hey Ulrich, sorry to bother you.
I have mistakenly released a tag 3.0.0-alpha.2 on master instead of branch 3.0. Because I'm not owner of the package on packagist I cant delete version. Can you please remove version 3.0-alpha.1
and 3.0.0-alpha.2
from packagist?
Thanks!
I'd like to see a way to enable explicit options, meaning either option "x" can be passed as an option, but option "y" would not be allowed or vice-versa (with one possibly being the default).
A real-world example might be:
script.php --read myfile.txt
or
script.php --write myfile.txt "test data"
The idea is that both options cannot coexist ahd either an Exception would be thrown or it would default to one.
It could even be expanded to multiple arguments or operands.
Any thoughts?
Hi,
According to https://secure.php.net/supported-versions.php and https://secure.php.net/eol.php PHP 5.4 is dead since 2 years and 7 months and 5.5 since 1 year, 8 months.
Concerning 5.6 and 7.0, they only get security fixes and until the end of this year only.
At the same time, PHPUnit 4.8 is no longer supported, as for PHPUnit 5 for 2 months.
PHPUnit 6, which is the oldest version supported (for 1 year from now) only supports PHP >= 7.0
Maybe it could be worth considering dropping PHP 5.x versions and upgrading dependencies...?
A branch for a future version 4 release could be started, which would support PHP >= 7.1 (with PHPUnit 7 and PHP CS 3.2) ?
When possible, features could be backported to 3.x (for PHP 5.4 - 5.6), which branch would still be supported for a while, even when 4.0 will be released.
What do you think?
Note: I have some free time...
Hello Thomas,
Today I went through the hoops of upgrading a couple of scripts relying on an older version of GetOpt.PHP for the first time.
It was not a very difficult task, but I think it would be nice to make things a bit more obvious and better documented for other users (currently, the only info I could find is a short note in the changelog, which is is not enough IMO and also not so easy to find).
I would suggest adding a note in the README file, linking to more details in the documentation.
For the record, here's a list of issues I faced and what I needed to change in my code to get things to work after updating composer.json and downloading the new version:
Ulrichsg\Getopt
-> GetOpt
[changed in 50818ec]Getopt
-> GetOpt
[changed in 0b98797]Creating a single command with multiple required operands fails with error:
PHP Fatal error: Uncaught exception 'InvalidArgumentException' with message 'Operand var is multiple - no more operands allowed' in /var/www/html/cmscli/vendor/ulrichsg/get
<?php
require_once('vendor/autoload.php');
use \GetOpt\GetOpt;
use \GetOpt\Command;
use \GetOpt\Option;
use \GetOpt\Operand;
class testCommand extends Command
{
public function __construct()
{
parent::__construct( 'test', [ $this, 'handle'] );
$this->addOperand( new Operand( 'var', Operand::REQUIRED ) );
$this->addOperand( new Operand( 'vaL', Operand::REQUIRED ) );
}
public function handle()
{
die(__METHOD__);
}
} // class
$getopt = new GetOpt;
$getopt->addCommand( new testCommand );
$getopt->process();
if( $cmd = $getopt->getCommand() ) {
die('command is '.$cmdd);
}
I'd like to query why command names cannot contain spaces. Currently I receive an error similar to the following:
InvalidArgumentException: Command name has to be an alphanumeric string not starting with dash, found 'import apps'
I want a command called import apps
and another called import reviews
. The thought occurs I could just create an import command with an operand that accepts either apps or reviews. The reason I cannot do this, however, is because each of those commands accept a different set of options. That is, since the commands do not share the same options they cannot be combined.
Is there any technical reason at all why a command could not contain a space character? If so, could such a restriction be lifted without too much effort?
Hi,
There appears to be a small problem with optional arguments and default values.
Option::create('v', "verbose", GetOpt::OPTIONAL_ARGUMENT)
->setDescription("Set the verbosity of the job manager")
->setValidation('is_numeric')
->setDefaultValue(6)`
If I specify -v
the default value is 1. If I specify --verbose
I get "6" as loosely expected. If I specify -v4
, I get the same result as --verbose
.
$getopt = new Getopt(array(
new Option(null, 'arg1', Getopt::REQUIRED_ARGUMENT),
new Option(null, 'arg2', Getopt::REQUIRED_ARGUMENT),
));
$getopt->parse()
I was expecting this to throw an exception if the argument is not found. Instead nothing happens.
Hi.
According your manual for set description for options:
new Option('h', 'help')->setDescription('Show help text')
But when use get a error and also my IDE phpStorm show me setDescription() undefined. But i see this public function on Option class.
PHP Fatal error: Call to undefined function setDescription()
Code my test:
require __DIR__.'/../../vendor/autoload.php';
use Ulrichsg\Getopt\Getopt;
use Ulrichsg\Getopt\Option;
$getOpt = new Getopt(array(
new Option('u', 'user', Getopt::REQUIRED_ARGUMENT),
new Option('t', 'type_restore', Getopt::REQUIRED_ARGUMENT),
new Option('d', 'rsync_delete'),
new Option(null, 'help'),
new Option(null, 'version')->setDescription('Show version')
));
Apreciate help
First of all... great library.
Too bad I just had to spent two hours trying to get the advanced example with member access on instantiation working.
$getopt = new Getopt(array(
new Option('o', 'option', Getopt::REQUIRED_ARGUMENT)
->setDescription('Description of option')
->setDefaultValue('default')
));
I believe the second line should be:
$getopt = new Getopt(array(
(new Option('o', 'option', Getopt::REQUIRED_ARGUMENT))
->setDescription('Description of option')
->setDefaultValue('default')
));
HTH
Right now when calling addOption, you pass in as many arrays like this as you want:
array('a', 'longoption', Getopt::REQUIRED_ARGUMENT);
Or if you want to only have a long option you do: array(null, 'longoption', Getopt::REQUIRED_ARGUMENT); Or if you want to only have a short option you do: array('a', null, Getopt::REQUIRED_ARGUMENT);
It would be nice to be able to have this instead:
array('a')
array('longoption')
The code would then delegate to the existing addOption passing the arguments as necessary. If it is one character then it's a short option, otherwise long option.
And the Getopt::REQUIRED_ARGUMENT could be omitted because it could be set to a user-configurable (in the Getopt constructor perhaps) default value if nothing is provided in addOption.
Would make the code that uses Getopt cleaner.
In a small CLI tool I've been working on, I've used these two concepts differently than currently in use in this library.
To me:
Is this something you might consider? If so, I'd be happy to contribute code :)
Hi,
Found this great package out only yesterday and already love it.
I think it would be nice to allow custom validation error messages, instead of the standard "Operand %s has an invalid value", which does not really explain what is actually expected (especially in case of complex validations with closures).
The message could be provided as a second argument to Argument::setValidation()
method and made available in Option::setValue()
and Operand::setValue()
.
Behind the scene, a Validator object (instanciated in Argument::setValidation()
) could hold the validation callback and the error message (which could be overridden in case of complex validation).
I may work on it if you're interested in adding this feature to a future release.
While in the process of adapting one of my apps to make use of the new localized help in GetOpt 3.1, I noticed that GetOpt has several user-facing error messages which have not been localized. I would expect these strings to be translated as well, as they are part of the app's front-end.
Sample code, defining an Option with required or validated arguments:
$opt = new \GetOpt\GetOpt([
\GetOpt\Option::create('t', null, \GetOpt\GetOpt::REQUIRED_ARGUMENT)
->setValidation(function($arg) { return is_numeric($arg); })
]);
$opt->setHelpLang('fr');
try {
$opt->process();
} catch (\GetOpt\ArgumentException $e) {
echo $e->getMessage() . PHP_EOL;
}
Output, should be localized:
$ php test.php -z
Option 'z' is unknown
$ php test.php -t
Option 't' must have a value
$ php test.php -t x
Option 't' has an invalid value
I notice that an option with REQUIRED_ARGUMENT can be provided an empty string as a value, but when iterating over the options array this option is skipped. I believe this is because GetOpt ->getIterator() is only returning options where the value evaluates to a true boolean in PHP, and an empty string gets evaluated as false.
Is this intended behaviour? Should the test instead be changed to !is_null()?
Although a richly detailed output is displayed for global options, command options are completely omitted from the help text, making such options undiscoverable by the user using the help system! I propose the same level of detail be present in the help output for each command with options.
In 3.0, the library allows 2 methods to customize the output of getHelpText:
I hope you won't mind my saying so, but I'm not very keen on the proposed approach, particularly the second one, and I think this should be improved. Here's a few issues I see:
The custom Help class is better, but still does not allow easy reuse of code in the default templates.
A couple of suggestions for improvement:
Let me know your thoughts.
It would be useful to have this method in order to find out the script name outside of Getopt class. For example to be able to show the script version number (including script name) and without using $argv.
Now there is an alpha release. Next is to update the docs and get some people testing the new features as well as the migration from version 2.x.
In this thread I want to save my thoughts to not forget the documentation... Please add your problems that you have with version 3 here. Either it is just a documentation problem or we can create another issue.
Thanks for your help!
Sent from my OnePlus ONEPLUS A3003 using FastHub
The documentation has grown too large for the repo front page. Split it into multiple files and put it on Github Pages.
So I am not sure how the handler is called. I looked through the code and I don't see it used anywhere.
$opts = new GetOpt();
$opts->addCommand(
Command::create("test", [$this, "callTest"])
);
If I run $opts->process(array("test"));
my callback isn't fired. This is running inside of a composer script... not sure what is dependent on $argv or something else that isn't present in the script env.
The $opts->process();
works when run directly from a CLI script so there maybe some type of unsatisfied dependency. See above... There is no output or exception or error msg, it fails silently.
This makes it easier to instantiate an entire getopt instance with just a single array of everything I need. Would be happy to contribute code :)
Getopt checks with empty
if options are given. The empty
construct returns true for the string "0"
, so Getopt fails with an exception "Option must have a value", although the value is given.
It is quite common that an operand is required in a cli application. Is it possible to provide operand validation as well?
I mean: check for having the required count of operands and optionally define them with names so operands can be retrieved by name and not number.
For a CLI application with fixed set of operands it'd be useful if it was possible to describe them explicitly in "usage" message. I.e. instead of
Usage: copy [options] [operands]
Options:
--overwrite Overwrite existing file
I'd like to have a more meaningful message like
Usage: copy [options] <from> <to> [<optional-operand>]
Options:
--overwrite Overwrite existing file
In fact, this example brings the idea of operands specification alongside with the one for options. Like options, operands may also have names, be mandatory or optional and have default values.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.