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
Differencebetween Sessions and Cookies in PHP
How to Make Pdo Run Set Names Utf8 Each Time I Connect, in Zendframework
Artisan Migrate Could Not Find Driver
How to Password Protect Folder/Page Using PHP Without a Db or Username
Configure Multiple Databases in Zf2
How to Auto Call Function in PHP for Every Other Function Call
PHP Can't Connect to MySQL with Error 13 (But Command Line Can)
How to Place Two Forms on the Same Page
What Factors Make PHP Unicode-Incompatible
Remove Diacritics from a String
Get Nearest Places on Google Maps, Using MySQL Spatial Data
Handle Fatal Errors in PHP Using Register_Shutdown_Function()
PHP to Store Images in MySQL or Not