Pasar parámetros adicionales a usort callback


Tengo las siguientes funciones. Wordpress funciona, pero esta es realmente una pregunta de PHP. Ordenan mis objetos $term de acuerdo con la propiedad artist_lastname en los metadatos de cada objeto.

Quiero pasar una cadena a $meta en la primera función. Esto me permitiría reutilizar este código ya que podría aplicarlo a varias propiedades de metadatos.

Pero no entiendo cómo puedo pasar parámetros adicionales a la devolución de llamada de usort. Traté de hacer una función anónima de estilo JS, pero el PHP versión en el servidor es demasiado viejo y arrojó un error de sintaxis.

Cualquier ayuda - o un empujón hacia la esquina derecha del manual - agradecida. ¡Gracias!

function sort_by_term_meta($terms, $meta) 
{
  usort($terms,"term_meta_cmp");
}

function term_meta_cmp( $a, $b ) 
{
    $name_a = get_term_meta($a->term_id, 'artist_lastname', true);
    $name_b = get_term_meta($b->term_id, 'artist_lastname', true);
    return strcmp($name_a, $name_b); 
} 
Author: djb, 2011-11-22

5 answers

En PHP, una opción para un callback es pasar una matriz de dos elementos que contiene un identificador de objeto y un nombre de método para llamar al objeto. Por ejemplo, si $obj era una instancia de la clase MyCallable, y desea llamar al método method1 de MyCallable en $obj, entonces puede pasar array($obj, "method1") como una devolución de llamada.

Una solución que utiliza este tipo de devolución de llamada soportado es definir una clase de un solo uso que esencialmente actúa como un tipo de cierre:

function sort_by_term_meta( $terms, $meta ) 
{
    usort($terms, array(new TermMetaCmpClosure($meta), "call"));
}

function term_meta_cmp( $a, $b, $meta )
{
    $name_a = get_term_meta($a->term_id, $meta, true);
    $name_b = get_term_meta($b->term_id, $meta, true);
    return strcmp($name_a, $name_b); 
} 

class TermMetaCmpClosure
{
    private $meta;

    function __construct( $meta ) {
        $this->meta = $meta;
    }

    function call( $a, $b ) {
        return term_meta_cmp($a, $b, $this->meta);
    }
}
 22
Author: Daniel Trebbien,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-22 17:41:50

Creo que esta pregunta merece una actualización. Sé que la pregunta original era para la versión 5.2 de PHP, pero vine aquí buscando una solución y encontré una para las versiones más nuevas de PHP y pensé que esto también podría ser útil para otras personas.

Para PHP 5.3 y superiores, puede usar la palabra clave ' use' para introducir variables locales en el ámbito local de una función anónima. Así que lo siguiente debería funcionar:

function sort_by_term_meta(&$terms, $meta) {
    usort($terms, function($a, $b) use ($meta) {
        $name_a = get_term_meta($a->term_id, 'artist_lastname', true);
        $name_b = get_term_meta($b->term_id, 'artist_lastname', true);
        return strcmp($name_a, $name_b);  
    });
}

Algún código más general

Si desea ordenar un array solo una vez y necesita un argumento adicional puede usar una función anónima como esta:

usort($arrayToSort, function($a, $b) use ($myExtraArgument) {
    //$myExtraArgument is available in this scope
    //perform sorting, return -1, 0, 1
    return strcmp($a, $b);
});

Si necesita una función reutilizable para ordenar una matriz que necesita un argumento adicional, siempre puede envolver la función anónima, como para la pregunta original:

function mySortFunction(&$arrayToSort, $myExtraArgument1, $myExtraArgument2) {
    usort($arrayToSort, function($a, $b) use ($myExtraArgument1, $myExtraArgument2) {
        //$myExtraArgument1 and 2 are available in this scope
        //perform sorting, return -1, 0, 1
        return strcmp($a, $b);
    });
}
 75
Author: Bas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-08 13:42:17

Asumiendo que tienes acceso a objetos y estática (PHP 5 o superior), puedes crear un objeto y pasar los argumentos directamente allí, así:

<?php
class SortWithMeta {
    private static $meta;

    static function sort(&$terms, $meta) {
       self::$meta = $meta;
       usort($terms, array("SortWithMeta", "cmp_method"));
    }

    static function cmp_method($a, $b) {
       $meta = self::$meta; //access meta data
       // do comparison here
    }

}

// then call it
SortWithMeta::sort($terms, array('hello'));

Asumiendo que no tienes acceso a objetos/estáticos; podrías simplemente hacer un global:

$meta = array('hello'); //define meta in global

function term_meta_cmp($a, $b) {
   global $meta; //access meta data
   // do comparison here
}

usort($terms, 'term_meta_cmp');
 6
Author: Kato,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-22 18:20:20

Los documentos dicen que create_function() debería funcionar en PHP >= 4.0.1. ¿Esto funciona?

function term_meta_cmp( $a, $b, $meta )  {
    echo "$a, $b, $meta<hr>"; // Debugging output
}
$terms = array("d","c","b","a");
usort($terms, create_function('$a, $b', 'return term_meta_cmp($a, $b, "some-meta");'));
 3
Author: John Watson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-22 17:26:37

Esto no le ayudará en absoluto con usort() pero podría ser útil sin embargo. Puede ordenar la matriz utilizando una de las otras funciones de ordenación, array_multisort().

La idea es construir una matriz de los valores sobre los que estaría ordenando (los valores devueltos desde get_term_meta()) y multisort que contra su matriz principal $terms.

function sort_by_term_meta(&$terms, $meta) 
{
    $sort_on = array();
    foreach ($terms as $term) {
        $sort_on[] = get_term_meta($term->term_id, $meta, true);
    }
    array_multisort($sort_on, SORT_ASC, SORT_STRING, $terms);
}
 1
Author: salathe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-22 19:24:20