Pass Extra Parameters to Usort Callback

Pass extra parameters to usort callback

In PHP, one option for a callback is to pass a two-element array containing an object handle and a method name to call on the object. For example, if $obj was an instance of class MyCallable, and you want to call the method1 method of MyCallable on $obj, then you can pass array($obj, "method1") as a callback.

One solution using this supported callback type is to define a single-use class that essentially acts like a closure type:

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

Can I pass additional parameters into an inline usort function?

Using the use keyword:

$external_variable = TRUE;

usort($array, function($a, $b) use($external_variable) {
// do sorting stuff based on $external_variable
});

http://php.net/manual/en/functions.anonymous.php

Closures may also inherit variables from the parent scope. Any such variables must be passed to the use language construct. From PHP 7.1, these variables must not include superglobals, $this, or variables with the same name as a parameter.

How to pass usort() a parameter?

Call it with a closure:

$sort_text='apple ipad';
usort(
$arr,
function ($a, $b) use ($sort_text) {
if(!strpos($a["p_title"], $sort_text)) {
return -1;
}
return 1;
}
);

and you can pass additional arguments with the use clause

usort with extra parameters to determine the exact type or sort needed

Here is an example of a function that condenses your switch statement. Warning untested but should do the trick.

function photoStort(array &$photos, $key, $order) {
if ($order !== 'desc' && $order !== 'asc') {
return false;
}

usort($photos, function($a, $b) use ($key, $order) {
$t1 = $a[$key];
$t2 = $b[$key];

if (is_string($t1) && is_string($t2)) {
if ($order === 'asc') {
return strcmp($t1, $t2);
} else {
return strcmp($t2, $t1);
}
} elseif (is_int($t1) && is_int($t2)) {
if ($order === 'asc') {
return $t1 - $t2;
} else {
return $t2 - $t1;
}
} else {
trigger_error('Invalid type in photoSort!', E_WARNING);
}
});
}
$photos = array(/* Photos */);

//ex 1
photoSort($photos, 'photoname', 'asc');

//ex 2
photoSort($photos, 'id', 'desc');

PHP 5.2 solution

function usortCallback($a, $b, $key, $order) {
$t1 = $a[$key];
$t2 = $b[$key];

if (is_string($t1) && is_string($t2)) {
if ($order === 'asc') {
return strcmp($t1, $t2);
} else {
return strcmp($t2, $t1);
}
} elseif (is_int($t1) && is_int($t2)) {
if ($order === 'asc') {
return $t1 - $t2;
} else {
return $t2 - $t1;
}
} else {
trigger_error('Invalid type in photoSort!', E_WARNING);
}
}

function photoSort(array &$photos, $key, $order) {
if ($order !== 'desc' && $order !== 'asc') {
return false;
}

usort($photos, create_function('$a, $b', 'return usortCallback($a, $b, "' . $key . '", "' . $order . '");'));
}

PHP's USORT Callback Function Parameters

To sort anything you need a means to compare two items and figure out if one comes before the other. This is what you supply to usort. This function will be passed two items from your input array, and returns the order they should be in.

Once you have a means to compare two elements, you can use sort-algorithm-of-your-choice.

If you are unfamiliar, you might like to look at how a simple naive algorithm like bubblesort would use a comparison function.

Behind the scenes, PHP is using a quicksort.

PHP additional parameters to usort

Since you're using an anonymous function, you can use it as a closure like this:

$filter = <whatever>;
usort($this->data, function($arr1, $arr2) use ($filter) {
return ($arr1[$filter] > $arr2[$filter]) ? 1 : -1;
});

Variable variables as parameters of custom function in usort()

Resolving dynamic names of variables is something that happens at runtime, rather than interpreter (aka compile) time. Therefore, you can not pass it as dynamic paramaters which you expected to be able to do.

Given that, this is not possible for one simple reason: Even if you would manage to pass different names at compile time, it would only be true for one set of values to compare. What would keep the callback-call from passing a<b, then a>b, then a==b (imagine them as values)? Nothing, and exactly that would happen.

That being said, you can try and validate which value is smaller before passing it to the final callback, but this only adds an extra layer rather than always sorting the same way (or even sorting at all):

usort($dataset, function($a, $b)
{
if ($a > $b) {
return $b <=> $a;
}
return $a <=> $b;
});

var_dump($dataset);

// output
array(3) {
[0]=>
int(3)
[1]=>
int(1)
[2]=>
int(7)
}

I am fully aware that this does not solve your problem at all. I am just trying to demonstrate that it wont even work that way.

I think the key fact here is that you define the sort mechanism in your callback, and hence you have to make sure that you sort it ascending or descending in that definition, since that is what it exists for!

And on a side note I think sorting callbacks became really easy to create in PHP since the spaceship operator:

// defines: sort ASC
usort($dataset, function($a, $b) { return $a <=> $b; });
// defines: sort DESC
usort($dataset, function($a, $b) { return $b <=> $a; });

And even more so with the arrow functions since PHP 7.4:

// ASC
usort($dataset, fn($a, $b) => $a <=> $b);
// DESC
usort($dataset, fn($a, $b) => $b <=> $a);

In conclusion, I fully understand where you are coming from, but maybe you are trying to solve a problem that is not even really there?

usort encrypted data by selectable columns (table sorting)

I can't pass the field to sort or it's direction into it.

Actually, you can. There is an example:

<?php
// Example data
$data = array(
array('name' => 'Gamma', 'val' => 25),
array('name' => 'Beta', 'val' => 5),
array('name' => 'Alpha', 'val' => 10)
);

function sortme(&$array, $onfield, $isdesc) {
usort($array,
function($a, $b) use ($onfield, $isdesc) { // 'use' keyword allows to reference external variables from the inside
// custom method to obtain and comapre data;
$v1 = isset($a[$onfield]) ? $a[$onfield] : NULL;
$v2 = isset($b[$onfield]) ? $b[$onfield] : NULL;

if ($v1 < $v2) return ($isdesc ? 1 : -1);
elseif ($v1 > $v2) return ($isdesc ? -1 : 1);
else return 0;
// Note: the conditions above can be replaced by spaceship operator in PHP 7+:
// return $isdesc ? ($v2 <=> $v1) : ($v1 <=> $v2) ;
}
);
}

sortme($data, 'name', false); // sort by `name` ascending
print_r($data); // Alpha -> Beta -> Gamma

sortme($data, 'val', true); // sort by `val` descending
print_r($data); // 25 -> 10 -> 5

PHP usort() expects parameter 2 to be a valid callback, not in a class

If the code is not in a class, but you are using a namespace, usort expects the second parameter to have that namespace defined. But not in an array in similar style to using usort in a class.

This worked for me, where 'cmp' is the sorting function:

usort($arrayToSort, 'My\Full\Namespace\cmp');


Related Topics



Leave a reply



Submit