Un'alternativa a una serie di funzioni?

1

Sto programmando un'app (php) che richiede una lunga lista di funzioni simili ma diverse, chiamate da un set di chiavi :

$functions = [
    "do this" => function() {
        // does this
    },
    "do that" => function() {
        // does that
    }
] 
etc.

Ho scelto di posizionare le funzioni simili in un array perché non sono simili sufficienti - ottenere lo stesso risultato con un'unica grande funzione che è piena di istruzioni condizionali non funzionerà. E devo essere in grado di chiamarli solo con il tasto , ad esempio:

$program = ["do this", "do that", "do this"];
foreach ($program as $k => $v) {
    $functions[$v]();
}

Questa struttura di funzioni-array sta causando molti problemi, ad esempio ho difficoltà a chiamare una funzione di matrice da un'altra funzione di matrice , ad es. questo non funziona:

"do that" => function() {
    $functions["do this"]();
}

né questo:

"do that" => function() {
    global $functions;
    $functions["do this"]();
}

o questo:

"do that" => function($functions) {
    $functions["do this"]();
}

$functions["do that"]($functions);

Credo che potrei avere una funzione gigante con una lunga istruzione :

function similar_functions($key) {
    switch ($key) {
        case "do this":
            // does this
        break;
        case "do that":
            // does that
        break;
    }
}

Ma quello non sembra davvero una buona pratica. O forse lo è?

Quindi, quali sono le mie alternative? Devo andare con la struttura degli switch? O c'è un'altra soluzione migliore?

    
posta Roy 11.02.2014 - 12:21
fonte

6 risposte

3

Espansione sul commento di @ lortabac:

Puoi passare i puntatori alle funzioni semplicemente passando il nome della funzione, ad esempio:

function fn1()
{
    // ...
}

function fn2($fn)
{
    $fn();
}

fn2(fn1);

Quindi dovresti essere in grado di popolare la tua matrice in questo modo:

$functions = [
    "do this" => fn1,
    "do that" => fn2
]

oppure, se si desidera essere in grado di chiamare le funzioni utilizzando i riferimenti impostati nell'array, è possibile definire prima l'array, quindi scrivere le funzioni, quindi impostare i riferimenti alle funzioni in l'array dopo.

    
risposta data 11.02.2014 - 15:30
fonte
1

Prima di tutto, secondo il principio DRY, dovresti provare a rendere le tue funzioni ancora più simili, in modo che possano condividere il maggior numero possibile di codice. Ciò renderà la gestione della base di codice abbastanza semplice, che non può essere detta in merito al numero di funzioni "simili ma diverse".

La possibile soluzione al tuo problema è racchiudere tutte le tue funzioni in una classe e renderle pubblicamente richiamabili con un solo nome. Il modo più pulito per farlo nella tua situazione è definire il metodo call , che chiamerà quindi la funzione appropriata, trovata usando il metodo magico __get . È bello ed è sicuro (beh, dipende dall'implementazione).

    
risposta data 21.02.2014 - 15:53
fonte
1

Stai essenzialmente chiedendo quando e come filiale . Il mio suggerimento generale sarebbe:

Con un approccio orientato agli oggetti (secondo i pattern), la decisione di ramificazione potrebbe essere controllata da una classe SomethingStrategyManager , che ti darà un'istanza di ISomethingStrategy . Quindi eseguirai il metodo ISomethingStrategy doTheThing .

In pseudo-codice molto generico:

interface IMyStrategy:
  method doTheThing(string name); //returns a BOOLEAN value
  ... //maybe this interface can have more methods?

class MyStrategyManager:
  method getStrategyForSomeArgs(int a, string c) //returns IMyStrategy
     if (a % 2 == 0) return new EvenNumberStrategy();
     else if (a.isPrimeNumber) return new PrimeNumberStrategy();
     else if (c == "CustomSomething") return new CustomStrategy();
     else return new DefaultStrategy();    

...

// Using the strategies:
IMyStrategy strategy = MyStrategyManager.getStrategyForSomeArgs(3, "foo");
BOOL success = strategy.doTheThing("john smith");
... 
    
risposta data 25.02.2014 - 20:56
fonte
0

Potresti creare una classe che racchiuda tutte le tue funzioni e poi chiamarle come metodi dell'oggetto

class SimpleFunctions {

  public function doThis() {
    // Do this
  }

  public function doThat() {
    // Do that
  }

  public function doThisInThat() {
    // Do this in That
    $this->doThis();
  }
}

$funcs = ['doThis', 'doThat', 'doThisInThat'];
$simpleFunctions = new SimpleFunctions();
foreach($funcs as $f) {
  if(!method_exists($simpleFunctions, $f))
    throw new \Exception(sprintf("Method %s not found in %s", $f, get_class($simpleFunctions));

  $simpleFunctions->$f();
}
    
risposta data 24.02.2014 - 09:32
fonte
0

Penso che, nel tuo ciclo FOREACH, puoi aggiungere

$method = '_' . <function name><key>;

if (method_exists($this, $method)) {
    $this->$method();
}
else {
    show_error('Could not load Method' . $method);
}

Algorithm / Logic: la variabile '$ method' memorizzerà il nome della funzione e la chiave disponibile che alla fine può funzionare come nome di un metodo. La condizione IF controlla semplicemente la disponibilità dello stesso metodo e la apre se il metodo esiste altrimenti genera un errore.

L'aspetto di una classe completa sarà:

public function your_function()
{
        foreach ($program as $k => $v) {
            //$this->call_function($v); // add 'call_function' in your loop
            $method = '_' . fn.$v; //<function name><key>

            if (method_exists($this, $method)) {
                $this->$method();
            }
            else {
                show_error('Could not load template ' . $method);
            }
        }
}   

public function _fnkey()
{
    echo "In Function 1";
}   

Spero che questo sia utile!

    
risposta data 24.02.2014 - 10:55
fonte
0

Penso che un modo migliore sia di cambiare la matrice in namespace. In questo modo puoi utilizzare nomi di funzioni normali e chiamate normali da altre funzioni.

Quando è necessaria la chiamata dinamica - usa il riferimento.

namespace foo {
  function f1($a) { print "1\n"; };
  function f2($a) { print "2\n"; f1(3); };
}
namespace bar {
  $f = '\foo\f2';
  $f(2);
}
    
risposta data 25.02.2014 - 10:22
fonte

Leggi altre domande sui tag