2012-07-03 11 views
40

que tiene una función que ordena los datos en una matriz multidimensional, como se muestra a continuación:función usort en una clase

<?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); 
?> 

Cuando corro esto, funciona como se esperaba, la devolución de los datos ordenados por nombre, ascendente. Sin embargo, necesito usar esto en una clase.

<?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"]); 
    } 
} 
?> 

Cuando utilizo esto, me sale el siguiente mensaje de advertencia: Advertencia: usort() espera parámetro 2 sea una devolución de llamada válida, la función 'order_new' no se encuentra o el nombre de función no válida.

cuando pongo la función order_new en la función changeOrder que trabaja muy bien, pero tengo problemas con Fatal error: No se puede redeclare order_new(), así que no puedo usar eso. ¿Alguna sugerencia?

+1

De alguna manera creo que te has perdido [esta respuesta] (http://stackoverflow.com/a/6054036/1229023) al buscar problemas similares, ¿no?) – raina77ow

+0

Lo vio, pero el nombre de la clase no funcionó. $ esto lo hace. – Marinus

+0

¿Hizo esta función estática antes de intentar llamarla con el nombre de clase? – raina77ow

Respuesta

80

order_new no es un método de clase una función global. A medida que el PHP-Manual sugieren que puede usar en este caso

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

o declarar order_new estática y utilizar

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

'usort ($ data, array (" MyBundle \ PathTo \ MyClass "," orderNew "));' si usa espacios de nombres –

+0

@limonte Olvidó escapar de las barras diagonales invertidas ... – tmuecksch

7

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

+0

Funciona un amuleto, gracias – Marinus

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

es lo que quiere cuando se hace referencia a una función en la instancia de la clase. Ver 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 a tener en cuenta es que si la variable se pasa a su método de referencia, usort () parece ejecutarse en el contexto de la variable referenciada y no su método actual. Por lo tanto, es necesario proporcionar el espacio de nombres completo en su referencia de clase de este modo:

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

Usted se olvidó de escapar de las barras invertidas ... – tmuecksch

+1

Interesante. Funciona en mi proyecto tal cual, pero con comillas simples. He actualizado para reflejar eso. – beltashazzar

+1

Muchas gracias. En mi caso, utilicé comillas dobles. – 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

Sé que este es un hilo viejo, pero me encontré con otra instancia hoy que podrían beneficiarse de otro enfoque. Tuve un caso en el que quería usar una clave específica para poder resumir la función de soporte real. Esto llevó a encontrar una versión que utilizara una función de contenedor para devolver una función anónima utilizando la palabra de comando 'usar' para proporcionar el nombre de la clave utilizada para clasificar en mi clase. (en mi caso, es una clave en una propiedad en una clase [anidada] que está asignada a una de las propiedades de clase donde estoy haciendo la clasificación, es decir, estoy ordenando instancias basadas en una propiedad en una instancia de 'dimensiones' asignado a una propiedad de 'elementos' y quiere poder ordenarlos por ancho, alto, longitud o peso, por ejemplo). Luego de obtener su función para la devolución de llamada, sólo tiene que llamar a esta función derivador con el nombre clave que desea utilizar para ordenar el resultado:

/** 
* 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!'); 
} 

Esto permite que llame usando local, ya sea estática o auto ::: : (concebiblemente, podría incluso incluirlo como una función no estática en este caso, ya que lo único que me preocupa es obtener la llamada, pero se devuelve la función) Otro beneficio que pronto descubrí es que mi objeto de dimensiones también tiene algunos 'cálculos 'campos tales como circunferencia, volumen y peso dimensional. Pero un problema es que el peso dimensional varía dependiendo de si está enviando un artículo a nivel nacional o internacional, por lo que necesito decirle a mi función 'calculateDimensionalWeight' si debe usar el valor para envío internacional o no.Bueno, usando este método, puedo hacerlo simplemente pasando un parámetro adicional a la función de envoltura y agregando el parámetro adicional a las variables de uso. Puesto que también es necesario para asegurarse de que estos valores han sido calculados antes de hacer cualquier comparación, puedo provocar que en mi función basada en la clave:

/** 
* @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: el cálculo de los valores de esta manera crea por encima mientras todos menos el primero y los últimos elementos de cualquier lista se calcularán técnicamente dos veces, lo cual es redundante, pero en este caso mis listas no son largas y, en algunos casos, debo comparar dos elementos cuando hago bin-sorting, por lo que aún es preferible. Para conjuntos de datos grandes, probablemente sería más prudente calcular previamente valores externos al método de clasificación.

Cuestiones relacionadas