变量变量作为 usort() 中自定义函数的参数

Variable variables as parameters of custom function in usort()

提问人:NulisDefo 提问时间:2/21/2020 最后编辑:mickmackusaNulisDefo 更新时间:8/15/2022 访问量:330

问:

我一直在玩,看看我是否可以在 PHP 中设置一个更动态的方法。

usort(
    $dataset,
    function($a, $b){
        return strcasecmp($a[$this->parameters], $b[$this->parameters]);
    }
);

此行将按字母降序对数组元素进行排序。但是,如果我们要交换变量,无论是否在或我们都会得到相反的效果(降序)。$a$bfunction($a, $b)($a[$this->parameters], $b[$this->parameters])

正如我所研究的那样,PHP中存在“变量”之类的东西。这方面的一个例子可能是:

$a="hello";
$$a="oops";
echo($hello);die;

但是,如果我同样尝试在上面的行代码中实现它,则会出现错误。

$first = 'b';
$second = 'a';
usort($dataset, function($$first, $$second){ return strcasecmp($a[$this->parameters], $b[$this->parameters]); });

错误:。Parse error: syntax error, unexpected '$', expecting variable (T_VARIABLE)

这个想法是能够根据 iff 语句结果逆转效果以重新定义和变量。否则,将需要复制几乎相同的代码。$first$second

我错过了什么吗?也许还有其他方法可以实现这一目标?

php usort 函数参数 变量 签名

评论

0赞 Mark 2/21/2020
尝试function(${$first}, ${$second})
2赞 Alex Barker 2/21/2020
我想我不明白你为什么要这样做......你想解决什么问题?如果只是更改排序顺序,请调用单独的函数或传入 use 参数来表示方向。
0赞 NulisDefo 2/21/2020
@MarkOverton 相同的结果。
0赞 NulisDefo 2/21/2020
@AlexBarker 当然,只需进行函数调用即可获得相同的结果。我刚刚遇到了变量,并试图更好地理解它们/查看它们的极限(尽管我不确定您所说的“使用参数”是什么意思)
0赞 Alex Barker 2/21/2020
@NulisDefo,我明白,这是一个有效的问题。您可以使用函数参数做的唯一有趣的事情是(又名解包运算符)和使用类似符号的可变参数函数。参见:wiki.php.net/rfc/variadics & wiki.php.net/rfc/argument_unpacking 与此相关的是,由于意外的副作用类型问题,变量变量通常是一个坏主意。每当你执行动态代码时,你都应该停下来问问自己,你是否能做出更好的设计选择。...

答:

2赞 ArSeN 2/21/2020 #1

解析变量的动态名称是在运行时发生的,而不是在解释器(又名编译)时发生的。因此,您不能将其作为您期望能够执行的动态参数传递。

鉴于此,这是不可能的,原因很简单:即使您在编译时设法传递不同的名称,也只能比较一组值。什么会阻止回调调用通过,那么,然后(将它们想象为值)?什么都没有,而且确实会发生。a<ba>ba==b

话虽如此,您可以在将值传递给最终回调之前尝试验证哪个值更小,但这只会增加一个额外的层,而不是总是以相同的方式排序(甚至根本不排序):

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

我完全知道这根本不能解决您的问题。我只是想证明它甚至不会以这种方式工作。

我认为这里的关键事实是你在回调中定义了排序机制,因此你必须确保在该定义中对它进行升序或降序排序,因为这就是它存在的目的

顺便说一句,我认为自从宇宙飞船操作员以来,在 PHP 中创建排序回调变得非常容易:

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

自 PHP 7.4 以来的箭头函数更是如此:

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

总之,我完全理解你来自哪里,但也许你正在试图解决一个甚至不存在的问题?

1赞 Alex Barker 2/21/2020 #2

我想对@ArSeN的伟大答案进行一些扩展,以添加更多的计算机科学背景,说明为什么这根本不是“一回事”。如果你看一下函数是如何在处理器级别(ASM语言)实现的,你很快就会意识到,传递给函数的参数名称甚至没有在二进制程序中使用。他们真的只是为了让你的生活成为程序员。大多数调用约定在堆栈帧上实现函数参数作为函数之间的空间。它们在函数内部各自的内存偏移处被访问。大多数 C 书籍和课程都会详细介绍这个概念,但在简单的英语中,这意味着参数的名称无关紧要,因为最终的二进制文件只使用参数的顺序。这在PHP中已经被抽象得很远,但是,它仍然非常相关,如果您打算在专业水平上编程,您应该了解这一点。

0赞 mickmackusa 8/15/2022 #3

让我们备份这个 XY 问题的总线。在几乎每个用例中,实现变量在最坏的情况下是一种考虑不周的反模式,充其量是一种症状,即应该被数组类型的数据编码为非数组数据类型。

即使是高质量的IDE(开发人员编写代码的软件),变量变量也经常会混淆,因此使用这些有效的编码技术通常会在其他非常有用的代码编辑器中触发恼人的误报警告。

至于如何在调用时避免变量 - 只需提供一个有条件的正因子或负因子来影响三向比较的结果。usort()

代码:(演示)

$direction = 'asc';
$factor = $direction === 'desc' ? -1 : 1;
$c = 'columnName';

usort(
    $array,
    fn($a, $b) => $factor * ($a[$c] <=> $b[$c])
);

var_export($array);

根据具体情况,调用 .(演示array_multisort())

$direction = 'desc';
$c = 'columnName';

array_multisort(
    array_column($array, $c),
    $direction === 'desc' ? SORT_DESC : SORT_ASC,
    $array
);

var_export($array);

最后,如果你正在寻找一个健壮的、通用的动态排序函数,你可能会受到我的回答的启发,即使用指定的排序规则对多个列上的关联数组进行排序