Git Product home page Git Product logo

Comments (7)

sonwell avatar sonwell commented on June 27, 2024

You can probably just use exit or die, but if you really want to throw something, this is basically what I did for the coffeescript port:

class SystemExit extends Exception {
    function __construct($usage) {
        exit($usage . PHP_EOL);
    }
}
throw new SystemExit("test");

from docopt.php.

shabbyrobe avatar shabbyrobe commented on June 27, 2024

Sorry, this reply ended up turning into a bit of a braindump. I think I understand my the issue a bit better now as a result though, so thanks for poking me into action!

Commence dumpage in 3... 2... 1...


The main issue is I want it to be possible, though not necessary, to take full responsibility for error output and exiting in the calling code. For example, in python, you can have it both ways and the client code is nice, clean, idiomatic python:

# this will exit with invalid input, but without a backtrace:
args = docopt(blah blah blah)

# full control of output and status:
try:
    args = docopt(doc)
except DocoptExit:
    print "Whatever I want, whenever I want, but it still quits if I don't"
    exit 9

# lovely!

You can suppress or modify output(1), have a custom exit status, whatever you like.

In PHP, die() doesn't give you this option as it's uncatchable. The SystemExit exception ticks all the boxes, but we don't get access to it in PHP. I'm trying to think of the smallest possible way to emulate the flexibility the python version has with the least impact on client code.

My first version of the PHP port looked like this:

<?php
try {
    $args = Docopt\docopt($doc);
}
catch (Docopt\ExitException $ex) {
    echo $ex->getMessage();
    exit(1);
}

If you didn't catch it, you got backtraces on your command line, which is no good, but you did get full control of the output and status.

The next attempt looked - actually, looks, at the time of writing - like this:

<?php
$args = Docopt\docopt($doc);
if ($arguments === false)
    exit(1);

The catch is moved into the Docopt\docopt() function. You can control the output, but only if you subclass Docopt\Handler and override handleExit() or use output buffering. I absolutely hate this "solution", hence why I'm furtively seeking a better one!

Anyway, the best I have so far is to add a flag to docopt to disable auto-exiting, then change the return of Docopt\docopt() to a result object that implements ArrayAccess. I'm not overly fond of this idea, but I'm more fond of it than my previous two attempts and it does seem to support my main requirement: that the client can, but does not have to, assume full control of the exiting and output:

<?php
// auto-exit and auto-output if input is invalid:
$result = Docopt\docopt($doc);

// don't auto-exit; output and status are the calling code's responsibility:
$result = Docopt\docopt($doc, array('exit'=>false));
if (!$result->success) {
    echo "Nah, didn't work";
    exit($result->status ?: 1);
}

echo $result['-q'];


1^ This is not 100% true - the exit that happens for --version and --help can be caught but they still emit output before they raise. I don't want to mimic this caveat.

from docopt.php.

keleshev avatar keleshev commented on June 27, 2024

@shabbyrobe You noticed that DocoptExit works neat in python, but it is not in public API/docs—because I am unsure if anyone would ever like to catch this and mess with exit message/status.

So I would suggest echo "error message"; echo $printable_usage; exit(1) to be the replacement for DocoptExit.

from docopt.php.

shabbyrobe avatar shabbyrobe commented on June 27, 2024

It's more about being able to control where exit happens. It's kind of an offshoot of the old "only one return" holy war. I'm not necessarily in that camp - I do like my guard clauses - but having exit hidden off in a library doesn't suit my preference for guard clauses being obviously visible up the top of a block.

I really like docopt.py's way of doing it - the exits happen if you let them, but they don't have to. I've thought more about it and I think the response object example at the bottom of the previous post is the way to go. A response object will still behave just like a dictionary if it implements ArrayAccess, so the change will be transparent. I can also corral it down the bottom, so integrating changes from the python implementation will remain a fairly one-to-one affair.

I guess I really just want to make sure the PHP library gives me the option of working the way I want without imposing that on anybody else.

from docopt.php.

shabbyrobe avatar shabbyrobe commented on June 27, 2024

I've pushed a version of this. The object returned by Docopt\docopt() behaves exactly like an array:

<?php
$args = \Docopt\docopt($doc);
echo $args['--quiet'].PHP_EOL;
foreach ($args as $k=>$v) {
    echo $k.": ".json_encode($v).PHP_EOL;
}

But it also does exactly what I want (not that my code would look quite this terrible):

<?php
$args = \Docopt\docopt($doc, array('exit'=>false));
if (!$args->success) {
    echo $args->output.PHP_EOL;
}
else {
    echo $args['--quiet'].PHP_EOL;
}
exit($args->status);

I'm going to leave the issue open just for the time being to make sure it's front and center that this may not be 100% finalised, but I think by talking through it here I've arrived at a good balance.

from docopt.php.

keleshev avatar keleshev commented on June 27, 2024

So you decided to raise an ExitException, and have the caller handle it? I'm asking because the same problem applies to almost every port. Every port has to decide how to handle exits. I wish to come up with some universal solution.

from docopt.php.

shabbyrobe avatar shabbyrobe commented on June 27, 2024

Nah, I just closed it because the issue has been sitting around for long enough and the current implementation in PHP allows you to have it both ways - you can let docopt handle the exits or catch them yourself by setting the 'exit' option. I think this is a good enough compromise for now. I'll revisit it if someone raises it and provides a superior alternative, but I haven't had any problems with the current implementation and I've used it hundreds of times now :D

from docopt.php.

Related Issues (10)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.