Risolvere l’errore Undefined offset in PHP

Descriviamo una semplice tecnica per evitare l’errore “Undefined offset” con le funzioni Variadic in PHP7.

In questi giorni, ho avuto la necessità di ammodernare del codice PHP scritto un po’ più di dieci anni fa; all’epoca, la versione 4 del linguaggio all’epoca ancora largamente diffusa. Per quanto ancora funzionante, le modifiche apportate a PHP hanno suggerito di intervenire per sfruttarne le innovazioni più moderne e per rimuovere il codice deprecato o, in qualche caso, addirittura rimosso. Tra le altre cose, in una classe del framework ho trovato questa funzione:

/**
 * Return the current object data. Maps to $this->getWhere().
 */
function &get() //($where='', $sort='', $limitOffset=-1, $limitNumRows=-1, $assocKey=null, $force=false, $distinct=false)    
{
list($where, $sort, $limitOffset, $limitNumRows, $assocKey, $force, $distinct) = func_get_args();
  if(!isset($where)) {$where = '';}
  if(!isset($sort)) {$sort = '';}
  if(!isset($limitOffset)) {$limitOffset = -1;}
  if(!isset($limitNumRows)) {$limitNumRows = -1;}
  if(!isset($assocKey)) {$assocKey = null;}
  if(!isset($force)) {$force = false;}
  if(!isset($distinct)) {$distinct = false;}
  return $this->getWhere ($where, $sort, $limitOffset, $limitNumRows, $assocKey, $force, $distinct);    
}

Questa implementazione mi ha sorpreso, perché nel contesto dell’applicazione non ho visto la necessità di usare né una funzione Variadic, né l’overloading; ho pensato che gli autori si preparassero a un refactoring del codice introducendo un’interfaccia generica e non volessero vincolarsi a una signature precisa. Questo programma, infatti, è stato scritto nel 2009, quando per molti sviluppatori non era ancora chiaro come usare correttamente le nuove funzionalità di PHP5.

Il motivo per il quale questa funzione ha richiamato la mia attenzione è che in PHP 7 genera l’errore di tipo notice“Undefined offset” quando il numero di parametri è minore del numero di argomenti della funzione list.

L’errore “”Undefined offset”

Per quanto non ami l’uso non giustificato della funzione func_get_args, in diverse circostanze possono risolvere elegantemente problemi altrimenti complicati. Ho preferito, quindi, conservare la scelta degli autori e cercare un modo compatto di risolvere il problema senza reintrodurre la dichiarazione esplicita dei parametri. La soluzione è stata semplice: per prima cosa si definisce un array con le proprietà di default; quindi si estrae la parte che eccede il numero dei parametri e infine la si accoda a questi in un unico array.

Il risultato è:

/**
 * Return the current object data. Maps to $this->getWhere().
 */
function &get() //($where='', $sort='', $limitOffset=-1, $limitNumRows=-1, $assocKey=null, $force=false, $distinct=false)    
{
  $defaultValues = array('', '', -1, -1, null, false, false);
  $args = func_get_args();
  $slice = array_slice($defaultValues, count($args));
  $fullArgs = array_merge($args, $slice);
  list($where, $sort, $limitOffset, $limitNumRows, $assocKey, $force, $distinct) = $fullArgs;
  return $this->getWhere ($where, $sort, $limitOffset, $limitNumRows, $assocKey, $force, $distinct);    
}

Non c’è più bisogno di verificare che le variabili siano effettivamente valorizzate, perché l’array su cui lavora la funzione list è completo. È richiesta una buona documentazione dei parametri e delle variabili su cui si sta lavorando, perché il codice è meno esplicativo; in compenso, questo semplice metodo risolve anche il problema dei valori di default, che func_get_args ignora, in quanto si limita a restituire una copia dei parametri ricevuti.

Conclusioni

Dopo questa semplice modifica, l’errore “Undefined offset” è definitivamente scomparso dai log. Questa tecnica si può applicare in molte situazioni simili anche per garantire la coerenza dei parametri di una funzione Variadic.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *