Reduce amount of conditional

4

I have a small function that delivers the value that has the highest priority, which for now is not defined anywhere, just by order as I evaluate the values:

public function obtenerValorMasImportante($datos = null) {

    if ($datos->getDato1()) {
        return 'dato1';
    }
    if ($datos->getDatoX()) {
        return 'datox';
    }
    if ($datos->getLoQueSea()) {
        return 'loquesea';
    }
    if ($datos->getOtraCosa()) {
        return 'otracosa';
    }
    return false;
}

The problem is simple: the code works, but What happens if I have 100 values? I would have to write 100 if and it's not a good idea, neither do ideas flow in this moment of the day.

I do not have much control over the $datos object, so it is not an option to modify it or add information to it.

How could I reduce the amount of if? or failing to make the code independent of the amount of values.

    
asked by Shaz 16.08.2016 в 21:37
source

3 answers

3

Based on the answers provided by Álvaro and Jesús (new answers are welcome), I ended up using this code, using Variable functions :

public function obtenerValorMasImportante($datos = null) {

    $valores = ['Dato1', 'DatoX', 'LoQueSea', 'OtraCosa'];

    foreach ($valores as $valor) {
        $metodo = 'get' . $valor;

        if ($datos->{$metodo}()) {
            return strtolower($valor);
        }
    }
    return false;
}
    
answered by 17.08.2016 / 03:28
source
5

It's not that eval is "bad", another disadvantage is that you can not easily capture errors , and the code is not portable to PHP 7, since you must necessarily include a return statement or return NULL.

Also, it is not necessary to use eval . You can dynamically call a method with call_user_func .

Although in the example the name of the method and the return value are less 'get' in the string and returning strtolower($nombre_metodo) , suppose that is not the case, and that we have to map method names invoked to disparate values :

function obtenerValor($datos = null) {    
    $mapMetodoAValor = [
        'Dato1' => 'valorRetorno1',
        'DatoX' => 'valorRetornoOtro',
        /* siguen más metodos => valor ...*/
    ];
    foreach($mapMetodoAValor as $metodo => $valor) {
        if(call_user_func([$datos, 'get' . $metodo])) {
            return $valor;
        }
    }
    return false;
}

If the values are always equal to strtolower($metodo) the array can be simpler, like the Álvaro example, but again, there is no need to use eval. Always prefer call_user_func

    
answered by 17.08.2016 в 00:23
4

Since all conditionals have the same basic structure, this is a case where you could use eval . The idea would be that you changed the function to do something like this:

  • Create an array with a list (sorted in order of priority) with the names of the attributes to be checked
  • Traverses the list from the first element to the last
  • With eval assign the value of the getter to an auxiliary variable
  • Check the value of the auxiliary variable
  • If it has any value, it returns the name of the array element.
  • The code would be like this:

    function obtenerValorMasImportante($datos = null) {    
        $aux = array("Dato1", "DatoX", "LoQueSea", "OtraCosa");
        $val = null;
        for ($x = 0; $x < count($aux); $x++) {
            eval('$val = $datos->get' . $aux[$x] . '();');
            if ($val)
                return strtolower($aux[$x]);
        }
        return false;
    }
    

    So now all you have to maintain is the list of attributes sorted by priority.

    Yes, I know there will be people who will say " but eval is diabolical and should not be used ", but that is not quite correct, especially for this case because you will be in control of everything what is going to be evaluated, so you do not run the risk of doing eval with an unknown entry.

        
    answered by 16.08.2016 в 23:47