2009-03-25 11 views
19

parametri di funzione chiamata possono essere emulate in PHP se scrivo funzioni come questoEmulazione di parametri di funzione con nome in PHP, buona o cattiva idea?

function pythonic(array $kwargs) 
{ 
    extract($kwargs); 
    // .. rest of the function body 
} 

// if params are optional or default values are required 
function pythonic(array $kwargs = array('name'=>'Jon skeet')) 
{ 
    extract($kwargs); 
    // .. rest of the function body 
} 

Oltre a perdere IntelliSense in IDE Quali sono gli altri aspetti negativi possibili di questo approccio?

Edit:

Sicurezza: Non dovrebbe essere la sicurezza di un non-problema, in questo caso, come le variabili estratte sono limitati a funzionare portata?

risposta

33

Suggerirei di utilizzare l'array associativo per passare parametri con nome, ma tenerli nell'array senza estrarli.

function myFunc(array $args) { 
    echo "Hi, " . $args['name']; 
    // etc 
} 

Ci sono un paio di motivi per questo. Guardando questa funzione, puoi chiaramente vedere che mi riferisco a uno degli argomenti passati nella funzione. Se li estrai e non ti accorgi dello extract() tu (o il prossimo ragazzo) sarai lì a grattarti la testa chiedendoti da dove provenisse questa variabile "$name". Anche se tu fai sai che stai estraendo gli argomenti alle variabili locali, è ancora un gioco di ipotesi fino a un certo punto.

In secondo luogo, garantisce che l'altro codice non sovrascriva gli argomenti. Potresti aver scritto la tua funzione aspettando solo di avere argomenti denominati $foo e $bar, quindi nel tuo altro codice, ad esempio, definisci $baz = 8;. In seguito, potresti voler espandere la tua funzione per prendere un nuovo parametro chiamato "baz" ma dimentica di modificare le altre variabili, quindi indipendentemente da ciò che viene passato negli argomenti, $baz sarà sempre impostato su 8.

Là sono alcuni vantaggi di utilizzare la matrice troppo (questi valgono anche per i metodi di estrazione o lasciando nella matrice): è possibile impostare una variabile nella parte superiore di ogni funzione chiamata $defaults:

function myFunc (array $args) { 
    $default = array(
     "name" => "John Doe", 
     "age" => "30" 
    ); 
    // overwrite all the defaults with the arguments 
    $args = array_merge($defaults, $args); 
    // you *could* extract($args) here if you want 

    echo "Name: " . $args['name'] . ", Age: " . $args['age']; 
} 

myFunc(array("age" => 25)); // "Name: John Doe, Age: 25" 

si potrebbe anche rimuovere tutti gli articoli da $args che non hanno un valore $default corrispondente. In questo modo sai esattamente quali variabili hai.

+2

Bel modo di gestirlo. Mi dispiace non aver letto la tua risposta prima di scrivere la mia. – Rolf

6

Nella mia esperienza, questo approccio è veramente utile solo se una delle due cose è vera

  1. per qualsiasi motivo attenuanti, la firma argomento è grande. Vado un 6 al massimo - non per una ragione specifica anche se sembra giusto - ma ammetto che questo numero è arbitrario.
  2. Tutti o molti dei tuoi argomenti sono facoltativi, ea volte è sufficiente impostare un valore per il quinto o qualcosa del genere. È fastidioso scrivere

Se uno di questi è vero per te, simulare params con un array associativo potrebbe essere la giusta implementazione. A parte sapere quando evitare l'estratto (o evitarlo del tutto) non riesco a pensare immediatamente ad altri aspetti negativi.

Ciò detto, spesso entrambi questi problemi possono essere risolti anche attraverso il refactoring.

8

Ecco un altro modo per farlo.

/** 
* Constructor. 
* 
* @named string 'algorithm' 
* @named string 'mode' 
* @named string 'key' 
*/ 
public function __construct(array $parameter = array()) 
{ 
    $algorithm = 'tripledes'; 
    $mode = 'ecb'; 
    $key = null; 
    extract($parameter, EXTR_IF_EXISTS); 
    //... 
} 

Con questo set up, si ottiene params di default, non si perde IntelliSense in IDE e EXTR_IF_EXISTS lo rende sicuro, semplicemente estraendo le chiavi degli array che sono già esistente come variabili.

(A proposito, la creazione di valori di default l'esempio che hai fornito non è buono, perché se una serie di param è fornito senza indice di un 'nome', il tuo valore di default è perduto.)

+0

Funzionerà per funzioni che non sono metodi di classe? (sul valore predefinito: l'ho ottenuto anche dopo aver postato la domanda) – Imran

+0

Certo, questo è solo un frammento di una mia classe. Funziona per qualsiasi cosa. – Mario

+1

Per favore, potresti spiegare come far funzionare intellisense con il tag '@ named'? Sto usando PHPStorm, che ha un ottimo intellisense, ma non riesco a farlo riconoscere un tag '@ named'. Non penso che sia un tag di commento PHP "reale", vero? Non è nella [lista PHPDoc dei tag] (http://www.phpdoc.org/docs/latest/index.html) – Rich

2

Nella mia esperienza , il lato negativo di questo metodo è più codice da scrivere. considerano qualcosa di simile:

function someFunc($requiredArg, $arg1 = "default11", $arg2 = "default2") { 

Per simulare questo comportamento quando si passa tutto in un array è necessario scrivere più codice e la "firma funzione" sarà meno "chiara ed evidente".

function someFunc($requiredArg, $optionalArgs) { 
    // see other answers for good ways to simulate "named parameters" here 

mi chiedo se sarebbe una buona idea per PHP per affrontare che in una futura release, forse avere qualcosa come Pascal o la sintassi VB disponibili per gli argomenti della funzione.

In ogni caso, trasmetto solo i parametri in un singolo array quando realmente necessario, ad esempio funzioni che hanno un set di parametri che è probabile che cambi molto durante lo sviluppo. Queste funzioni di solito hanno anche numerosi parametri.

1

Altri hanno già risposto ai tuoi altri punti, vorrei solo commentare l'aspetto della sicurezza.

Sicurezza: in questo caso la sicurezza non dovrebbe essere un problema, poiché le variabili estratte sono limitate all'ambito della funzione?

Sì e no. Il codice che hai scritto potrebbe (dipende se inizializzi sempre le tue variabili dopo questa chiamata) sovrascrivendo i tuoi vars. Esempio:

function pythonic(array $kwargs = array('name'=>'Jon skeet')) 
{ 
    $is_admin = check_if_is_admin(); // initialize some variable... 

    extract($kwargs); 

    // Q: what is the value of $is_admin now? 
    // A: Depends on how this function was called... 
    // hint: pythonic([ 'is_admin' => true ]) 
} 

Ciò che rende questo codice "tipo-di-sicuro" è che tu sei quello che sta chiamando - quindi l'utente non può fornire parametri arbitrari (a meno che non si reindirizza POST vars lì, ovviamente;).

Come regola generale si dovrebbe evitare tale magia. La linea con extract() potrebbe avere effetti collaterali indesiderati, quindi non dovresti usarla. In realtà, non riesco a pensare a un uso legittimo della funzione extract() in qualsiasi applicazione (non credo di averlo mai usato io stesso).

Problemi correlati