2012-07-03 9 views
40

Ho una funzione che ordina i dati in un array multidimensionale, come illustrato di seguito:funzione usort in una classe

<?php 
$data = array(); 
$data[] = array("name" => "James"); 
$data[] = array("name" => "andrew"); 
$data[] = array("name" => "Fred"); 

function cmp($a, $b) 
{ 
    return strcasecmp($a["name"], $b["name"]); 
} 

usort($data, "cmp"); 

var_dump($data); 
?> 

Quando ho eseguito questo, funziona come previsto, restituendo i dati ordinati per nome, ascendente. Tuttavia, ho bisogno di usarlo in una classe.

<?php 
class myClass 
{ 
    function getData() 
    { 
     // gets all data 
     $this -> changeOrder($data); 
    } 

    function changeOrder(&$data) 
    { 
     usort($data, "order_new"); 
    } 

    function order_new($a, $b) 
    { 
     return strcasecmp($a["name"], $b["name"]); 
    } 
} 
?> 

Quando uso questo, ottengo il seguente avvertimento: Attenzione: usort() si aspetta parametro 2 sia un callback, funzione valida 'order_new' non trovato o nome di funzione non valido.

quando ho messo la funzione order_new nella funzione changeOrder funziona benissimo, ma ho problemi con Fatal error: Can not ridichiarare order_new(), quindi non posso usare quella. Eventuali suggerimenti?

+1

In qualche modo penso che tu abbia perso [questa risposta] (http://stackoverflow.com/a/6054036/1229023) durante la ricerca di problemi simili, vero? – raina77ow

+0

L'ho visto, ma il nome della classe non ha funzionato. $ questo fa. – Marinus

+0

Hai reso statica questa funzione prima di provare a chiamarla con il nome della classe? – raina77ow

risposta

80

order_new è un metodo di classe non è una funzione globale. Come il PHP-Manual suggeriscono è possibile usare in questo caso

usort($data, array($this, "order_new")); 

o dichiarare order_new statica e utilizzare

usort($data, array("myClass", "order_new")); 
+14

'usort ($ data, array (" MyBundle \ PathTo \ MyClass "," orderNew "));' se usi spazi dei nomi –

+0

@limonte Hai dimenticato di scappare dalle barre retroverse ... – tmuecksch

7

Scelgo usort($data, array($this, "order_new"));

+0

Funziona un incantesimo, grazie – Marinus

5
usort($data, array($this,"order_new")); 

è ciò che si vuole quando si fa riferimento a una funzione nella vostra istanza di classe. Vedere callable

A method of an instantiated object is passed as an array containing an object at index 0 and the method name at index 1.

1

Una cosa da considerare è che se la variabile viene passata al metodo per riferimento, usort () sembra essere eseguito nel contesto della variabile di riferimento e non il metodo corrente. Pertanto, è necessario fornire il pieno spazio dei nomi nel vostro riferimento di classe in questo modo:

usort($data, ['My\NameSpace\MyClass', 'order_new']); 
+1

Tu ho dimenticato di scappare dai backslash ... – tmuecksch

+1

Interessante. Funziona nel mio progetto così com'è, ma con virgolette singole. Ho aggiornato per riflettere questo. – beltashazzar

+1

Grazie mille. Nel mio caso ho usato le virgolette. – tmuecksch

0
// If order_new is a NORMAL function 
usort($data, [$this, 'order_new']);  // self ref object, function name 

// If order_new is a STATIC function 
usort($data, [__CLASS__, 'order_new']); // string, function name 
0

So che questo è un vecchio thread, ma mi sono imbattuto in un altro caso di oggi che potrebbe trarre beneficio da un altro approccio. Ho avuto un caso in cui volevo utilizzare una chiave specifica in modo da poter astrarre la funzione di supporto reale. Ciò ha portato a trovare una versione che utilizza una funzione wrapper per restituire una funzione anonima che utilizza la parola di comando 'use' per fornire il nome della chiave usata per ordinare nella mia classe. (nel mio caso, è una chiave in una proprietà su una classe [nested] che viene assegnata a una delle proprietà della classe in cui sto facendo l'ordinamento, cioè sto ordinando le istanze in base a una proprietà in un'istanza di 'dimensioni' assegnato ad una proprietà di "articoli" e vuole essere in grado di ordinarli per larghezza, altezza, lunghezza o peso, ad esempio). Quindi per ottenere la funzione per la richiamata, è sufficiente chiamare questa funzione wrapper con il nome della chiave che si desidera utilizzare per ordinare il risultato:

/** 
* list of items 
* 
* @var Item[] 
*/ 
public $items; 

/** 
* @param string $key 
* @return \Closure 
*/ 
private static function keySort($key) { 
    return function ($ia, $ib) use ($key) { 
     if($ia->dimensions->$key == $ib->dimensions->$key) return 0; 
     return ($ia->dimensions->$key < $ib->dimensions->$key) ? -1 : 1; 
    }; 
} 

/** 
* return the list of items in the items array sorted by the value 
* of the property specified by $key 
* 
* @param string $key 
* @return Item[] 
* @throws \Exception 
*/ 
public function sortItemsByKey($key) 
{ 
    if(in_array($key, array('width', 'length', 'height', 'weight',))) { 
     return usort($this->items, static::keySort($key)); 
    } else 
     throw new \Exception(__METHOD__ . ' invalid sort key!'); 
} 

Questo mi permette di chiamarla locale utilizzando statica :: o di auto: : (presumibilmente, potrei anche avvolgerlo come una funzione non statica in questo caso poiché l'unica cosa di cui sono preoccupato è ricevere la chiamata ma la funzione è stata restituita) Un altro vantaggio che ho presto scoperto è che l'oggetto delle mie dimensioni ha anche un po 'di calcolato 'campi come circonferenza, volume e peso dimensionale. Ma un problema è che il peso dimensionale varia a seconda che tu stia spedendo un articolo a livello nazionale o internazionale, quindi devo dire alla mia funzione 'calculateDimensionalWeight' se deve utilizzare il valore per la spedizione internazionale o meno.Bene, usando questo metodo, posso farlo passando semplicemente un parametro addizionale alla funzione wrapper e aggiungendo il parametro aggiuntivo alle variabili use. Dal momento che ho anche bisogno di assicurarsi che questi valori sono stati calcolati prima di fare qualsiasi confronto, posso scattare che nella mia funzione in base alla chiave:

/** 
* @param string $key 
* @param bool $intl // only used for dimensional weight 
* @return \Closure 
*/ 
private static function keySort($key,$intl=false) { 
    return function ($ia, $ib) use ($key,$intl) { 
     switch($key) { 
      case 'girth': 
       $ia->dimensions->calculateGirth(); 
       $ib->dimensions->calculateGirth(); 
       break; 
      case 'dimweight': 
       $ia->dimensions->calculateDimensionalWeight($intl); 
       $ib->dimensions->calculateDimensionalWeight($intl); 
       break; 
      case 'volume': 
       $ia->dimensions->calculateVolume(); 
       $ib->dimensions->calculateVolume(); 
       break; 
     } 
     if($ia->dimensions->$key == $ib->dimensions->$key) return 0; 
     return ($ia->dimensions->$key < $ib->dimensions->$key) ? -1 : 1; 
    }; 
} 

/** 
* return the list of items in the items array sorted by the value 
* 
* @param string $key 
* @param bool $intl (only used for dimensional weight sorts on international shipments) 
* @return Item[] 
* @throws \Exception 
*/ 
public function sortItemsByKey($key,$intl=false) 
{ 
    if(in_array($key, array('value','collect', 'width', 'length', 'height', 'weight', 'girth', 'dimweight', 'volume'))) { 
     return usort($this->items, static::keySort($key,$intl)); 
    } else 
     throw new \Exception(__METHOD__ . ' invalid sort key!'); 
} 

NOTA: il calcolo dei valori in questo modo crea in testa, come tutti, ma il primo e gli ultimi elementi in qualsiasi elenco verranno calcolati tecnicamente due volte, che è ridondante, ma in questo caso le mie liste non sono lunghe e in alcuni casi, ho bisogno di confrontare due elementi quando si effettua l'ordinamento bin, quindi è ancora preferibile. Per dataset di grandi dimensioni, sarebbe probabilmente più saggio pre-calcolare valori esterni al metodo di ordinamento.

Problemi correlati