Closure and Magical Methods

Asked

Viewed 89 times

-1

Talk guys, it’s okay?

I am developing a note sending system, but as we learn something new every day I came across the following doubt:

I have a closure that treats some settings before calling the sending of the invoice in my system, but studying more deeply some tools I arrived at the magic method __invoke.

Let me give you a practical example(I will use an example code in both situations):

Example of configuration array:

$conf['modeloNota'] = "55"; //65 ou 55
$conf['ambiente']   = 1   ; //Homologação ou Produção

closure

$ret = function ($idcliente) use ($conf) {
    if(isset($conf['modeloNota']) && $conf['modeloNota'] == "65") {
        //Aqui vai a chamada da função para o envio da nota modelo 65
        $retorno = strtoupper('nfce');
    }else if(isset($conf['modeloNota']) && $conf['modeloNota'] == "55"){
        //Aqui vai a chamada da função para o envio da nota modelo 55
        $retorno = strtoupper('nfe');
    }else{
        $retorno = "Modelo de nota não definido";
    }

    return $retorno;
};

Using the magic method invoke, I came up with something like this:

class EnvioNota {
    public function __invoke($idcliente ,$conf) {

        if(isset($conf['modeloNota']) && $conf['modeloNota'] == "65") {
            $retorno = strtoupper('nfce');
        }else if(isset($conf['modeloNota']) && $conf['modeloNota'] == "55"){
            $retorno = strtoupper('nfe');
        }

        echo $retorno;
    }
}

$envio = new EnvioNota();
$envio(5, $conf);

The two work as expected, but what’s puzzling me is:

  • Which of the two methods is best considered when it comes to good programming practices?

  • About functions that require more amount of code it is recommended to use some of these approaches?

  • Is there any other way to create the same functions using other types of anonymous functions?

Edit:

Here is a real example: I have the following function within my Method class:

 $retornoLote = function ($empresa) use ($request){
    $chavenfce = $request->get('xml');
    $xmlAssinado = file_get_contents(storage_path('app/notas/'. preg_replace("/[^0-9]/", "", $empresa->cnpj) . '/' . date('mY') . '/assinadas/' . $request->get('xml').'.xml'));

    $config = [
       "atualizacao" => "2018-02-06 06:01:21",
       "tpAmb" => 2, // como 2 você emitirá a nota em ambiente de homologação(teste) e as notas fiscais aqui não tem valor fiscal
       "razaosocial" => $empresa->razaosocial,
       "siglaUF" => $empresa->endereco->uf,
       "cnpj" => MetodosNF::limpaMascaraCnpjCpf($empresa->cnpj),
       // "schemes" => "PL_008i2",
       "schemes" => "PL_009_V4",
       // "versao" => "3.10",
       "versao" => "4.00",
       "tokenIBPT" => "AAAAAAA",
       "CSC" => $empresa->nfcecsc1,
       "CSCid" => $empresa->nfceidtoken1,
    ];

    $configJson = json_encode($config);

    $filename = preg_replace("/[^0-9]/", "", $empresa->cnpj) . '.pfx';
    $certificadoDigital = file_get_contents(public_path() .  '/certificados/' . $filename);

    $tools = new \NFePHP\NFe\Tools($configJson, \NFePHP\Common\Certificate::readPfx($certificadoDigital, '1234'));
    $tools->model(65);

    try {
        $idLote = str_pad(100, 15, '0', STR_PAD_LEFT); // Identificador do lote
        $resp = $tools->sefazEnviaLote([$xmlAssinado], $idLote);

        $st = new \NFePHP\NFe\Common\Standardize();
        $std = $st->toStd($resp);

        if ($std->cStat != 103) {
            //erro registrar e voltar
            return array('status'=>1, 'mensagem'=>"[$std->cStat] $std->xMotivo");
        }
        $recibo = $std->infRec->nRec; // Vamos usar a variável $recibo para consultar o status da nota
    } catch (\Exception $e) {
        //aqui você trata possiveis exceptions do envio
        return array('status'=>1, 'mensagem'=>$e->getMessage());
    }

    //Salvar o XML no backup
    Storage::put('notas/'. MetodosNF::limpaMascaraCnpjCpf($empresa->cnpj) . '/' . date('mY') . '/retornoLote/' . $request->get('xml') .'.txt', "[$std->cStat] $std->xMotivo");

    try {
        $protocolo = $tools->sefazConsultaRecibo($recibo);
    } catch (\Exception $e) {
        //aqui você trata possíveis exceptions da consulta
        return array('status'=>1, 'mensagem'=>$e->getMessage());
    }

    try {
        $protocol = new \NFePHP\NFe\Factories\Protocol();
        $xmlProtocolado = $protocol->add($xmlAssinado,$protocolo);
    } catch (\Exception $e) {
        //aqui você trata possíveis exceptions ao adicionar protocolo
        return array('status'=>1, 'mensagem'=>$e->getMessage());
    }

    //Salvar o XML no backup
    Storage::put('notas/'. MetodosNF::limpaMascaraCnpjCpf($empresa->cnpj) . '/' . date('mY') . '/' . $chavenfce.'.xml', $xmlProtocolado);

    //Verifica o logo
    //Só funciona se for jpg
    if(file_exists(public_path() .  '/images/empresa' . \Auth::user()->idglobal .'.jpg')){
        $imagem = asset('images/empresa'. \Auth::user()->idglobal .'.jpg');
    }else{
        $imagem = "";
    }

    //Montagem do PDF
    $docxml = $xmlProtocolado;
    $pathLogo = $imagem;
    $danfce = new Danfce($docxml, $pathLogo, 0);
    $id = $danfce->monta();
    $pdf = $danfce->render();

    Storage::put('notas/' . MetodosNF::limpaMascaraCnpjCpf($empresa->cnpj) . '/' . $chavenfce.'.pdf', $pdf);

    return array('status'=>200, 'url'=>$chavenfce);
}

I thought I’d create a new class and reprogram this code fragment by throwing it into a class retornoLote, I’m studying a way to make this more "simple" and readable.

  • 2

    The issue issue that now may be different from the original, I responded based on what I was asking before. Wallace also. Although analyzing better nor occurred, it just doesn’t make sense in the question.

  • 1

    You are complicating something that is simpler, is encapsulating functions, and worsening the reading, the big problem of questions like this is because the scenario we can never see and automatically understand, perhaps, make as simple as possible, is much better.

2 answers

5

Which of the two methods is best considered when it comes to good programming practices?

I have only these two options or I can have my own options?

Insert/meme do Pânico na Band

Forget this good practice business. That’s for nothing if you don’t know what you’re doing, without really understanding what you’re dealing with, because, how you use what scenario. One of the reasons people are programming so badly and making applications so bad is because they think it’s enough for someone to say what’s good or bad and they don’t need anything else to do good code. If that were true programmers would start losing jobs, if the thing is so mechanical it doesn’t need so much programmer.

Without context everything is bad practice. And we don’t know what its context is, not just the application, the need, but also the type of project, under what conditions it’s being developed and other things that I don’t even remember, nor do I know that it’s important in this context (yes, it has contexts that are conditional by the context it is in). Without this information whatever, everything will be bad.

I think the two options are bad in what you can see because they are completely unnecessary. You want to stick to the news you have learned. This is not how you program it. The problem should ask for the solution, not the solution determine how it will solve the problem.

Plug com gambiarras para entrar na tomada em vez de entrar direto

About functions that require more amount of code it is recommended to use some of these approaches?

I’m not sure I understand what that means, but I’ve already said they’re both bad.

Is there any other way to create the same functions using other types of anonymous functions?

It certainly exists, but for what? You don’t need it. The day you have a problem that requires a closure you use, but this problem is solved with a too simple function with a very simple parameter. So the second is even better, but unnecessary to have a class just to have a function inside.

Something like this was enough (I didn’t write it better because I didn’t understand what this function should do, and the code isn’t even good yet):

function DescricaoTipoNota($modeloNota) {
    return $modeloNota == "65" ? "NFCE" : $modeloNota == "55" ? "NFE" : null;
}

I put in the Github for future reference.

People are creating very complicated, long, meaningless codes that hurt maintenance. And it’s getting worse every day.

The issue of the question shows nothing different from what was said in essence, it just shows that the code as a whole is extremely more complicated than it should be and makes several mistakes, even if it works, most of the time, but this is another matter. Part of the blame is the component you’re using that’s really bad (and I’m just talking based on the API I saw in the question, I don’t even know you in detail). I didn’t even see where closure would fit the code posted, it might be my mistake for the code to be too confused. And the edit made the question unclear.

  • Actually this is a code fragment that I used to illustrate, the function is really quite extensive, I’ll put one of the examples in the question.

  • @Alvaroalves did not understand the relationship between the use of closures and the "function to be very extensive". If it is quite extensive, it may not be the case to discuss what to use, but rather to encode better.

1


Which of the two methods is best considered when it comes to good programming practices?

It depends on how many times you will use the function. I would say Closures should be used only when you will need a callback, but the same will only be used in one place.

If I needed a callback function in more than one place, maybe I’d think about using the magic method __invoke. But still, __invoke is unnecessary, since you can work with functions.

Of course who some (rare) cases you can use __invoke, no problem. But I wouldn’t define a class with just one method __invoke. If the class did more things I might even think about it, but by default, if you’re going to use callback more than once, recommend using even functions.

In your case, it is evident that you are only using the callback once.

About functions that require more amount of code it is recommended to use some of these approaches?

I think you should use anonymous functions only when you need an instant callback (which will most often be used only once).

A small example is when you need to sort an array with a specific rule, but you won’t need to use that callback more than once, just at that moment.

You could do something like:

 $frutas = ['maçã', 'banana', 'melão'];

 // Ordena pelo tamanho da string
 usort($frutas, function ($a, $b) {
      return strlen($a) - strlen($b);         
 });

Is there any other way to create the same functions using other types of anonymous functions?

This question is confused. There is only one way to create anonymous functions: through closures.

A class implement the function __invoke does not make it an anonymous function.

__invoke according to the documentation:

The method __invoke() is called when a script attempts to call an object as a function.

I mean, it’s just a behavior modifier.

The class Closure (which is the instance returned when you assign an anonymous function to a variable), it also implements the method __invoke, but you can’t confuse the two things

  • Anonymous function is the function that has no name. It returns an instance of the class called Closure which, in turn, implements the magic method __invoke.

  • A class that implements __invoke can be called as function (ie you can put () in the variable, or use call_user_func_array). That is, it is just a behavior modifier: The class will behave like function when called as function.

  • Mr Downvoter, I come by way of this to solicit friendly feedback regarding your negative given in my answers. Thank you.

Browser other questions tagged

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