How to get around a GOTO problem in PHP

Asked

Viewed 255 times

0

I have a small package manager in the terminal of own use and that manages my Framework, and I am giving an improvement on it, and falls into a problem where I can not loop without using goto, as in the code below:

$stdin = fopen('php://stdin', 'r');
$rs_add_deps = fgetc($stdin);
$requires = [];
if ($rs_add_deps == 's') {
    add_req:
    echo "Digite o pacote completo:";
    $stdin = fopen('php://stdin', 'r');
    $countReq = count($requires);
    $requires[$countReq] = fgetc($stdin);
    goto test_add_req;
} else {
    end_add_req:
    var_dump($requires);
}
test_add_req:
echo "Adicionar outro pacote?";
$stdin = fopen('php://stdin', 'r');
$add_n_pack = fgetc($stdin);
if ($add_n_pack == 's') {
    goto add_req;
} else {
    goto end_add_req;
}

This script adds possible packages to the array $requires[] according to what the user defines that he wants, it works perfectly, knowing that the interaction is via terminal and that I will never know how many packages are and (he makes tests to know if the package is valid but I cleaned to be simpler example), there is a less crooked way to capture these values and add to the array?

Another second solution I have is this, but I found it much more complex than using the drip:

$stdin = fopen('php://stdin', 'r');
$rs_add_deps = fgetc($stdin);
$requires = [];
$countReq = 0;
$ask = false;
if ($rs_add_deps == 's') {
    while (true) {
        if (is_numeric($countReq) === 0) {
            echo "Digite o pacote completo EX: 'gm/bv4fphp':";
            $stdin = fopen('php://stdin', 'r');
            $requires[$countReq] = fgetc($stdin);
            $ask = true;
            $countReq += 1;
        } elseif (is_numeric($countReq) > 0) {
            if ($ask == true) {
                echo "Adicionar outro pacote?";
                $stdin = fopen('php://stdin', 'r');
                $add_n_pack = fgetc($stdin);
                if ($add_n_pack == 's') {
                    $ask = false;
                } else {
                    $countReq = 'get-out';
                }
            } else {
                echo "Digite o pacote completo:";
                $stdin = fopen('php://stdin', 'r');
                $requires[$countReq] = fgetc($stdin);
                $ask = true;
                $countReq += 1;
            }
        } else {
            var_dump($requires);
            break;
        }
    }
}

NOTE: This project is structured, 0 orientation, I did not want to leave this context in this project.

  • Kind of use a while(true) and give break when the entry is different from s?

  • 2

    You can create functions. But considering that this script of yours is very simple, I see no problem in leaving as is, if it works. GOTO is not the devil :)

  • @Andersoncarloswoss I tried with while(true), but found more complex than before

  • I’ve decided to leave my contribution to an image :D

1 answer

2


First, I really don’t understand why so many fopen, one enough, and the operation continues with fgetc within a while or in a recursion with functions, that is, you are opening several times the php://stdin needlessly, you could just use something like:

<?php
$stdin = fopen('php://stdin', 'r');

while (!feof($stdin)) {
    var_dump(fgetc($stdin));
}

Ready, you are in an infinite loop already, or you could simplify further and directly use the constant STDIN, thus:

<?php
while (!feof(STDIN)) {
    var_dump(fgetc(STDIN));
}

Now let’s go to your code

Your problem wasn’t even with the while or goto, is that there are flaws in your code that may or may not be the reason for not working as you want, for example:

echo "Digite o pacote completo EX: 'gm/bv4fphp':";
$stdin = fopen('php://stdin', 'r');

Here you ask to enter a path, but then use:

$requires[$countReq] = fgetc($stdin);

Which will only return the first letter and not the full path, because fgetc returns only the first character of something typed

I think what you want is something close to this:

<?php
$requires = [];

function pegar_resposta()
{
    return trim(fgets(STDIN));
}

function adicionar_pacotes()
{
    global $requires;

    if (empty($requires) === false) {
        echo "Adicionar outro pacote?";
        $resposta = pegar_resposta();

        if ($resposta === 's') {
            return;
        }
    }

    echo "Digite o pacote completo EX: 'gm/bv4fphp':";

    $resposta = pegar_resposta();

    if ($resposta === 's') {
        return;
    }

    $requires[] = $resposta;

    adicionar_pacotes();
}

adicionar_pacotes();

print_r($requires);

It is very simplified, the following function I created so that you have the adjustments only in one location:

function pegar_resposta()
{
    return trim(fgets(STDIN));
}

And Trim is for removing spaces and line breaks, so you can catch the s when you wish to finish.

With while would look like this:

<?php
$requires = [];

function pegar_resposta()
{
    return trim(fgets(STDIN));
}

while (true) {
    if (empty($requires) === false) {
        echo "Adicionar outro pacote?";
        $resposta = pegar_resposta();

        if ($resposta === 's') {
            break;
        }
    }

    echo "Digite o pacote completo EX: 'gm/bv4fphp':";

    $resposta = pegar_resposta();

    if ($resposta === 's') {
        break;
    }

    $requires[] = $resposta;
}

print_r($requires);

Browser other questions tagged

You are not signed in. Login or sign up in order to post.