PHP数组比较:为什么数组的回调函数必须返回-1、0或1?

PHP数组比较:为什么数组的回调函数必须返回-1、0或1?,php,arrays,multidimensional-array,comparison,Php,Arrays,Multidimensional Array,Comparison,在文档的注释中指出,回调函数必须返回-1($a$b) 回调函数的目的是比较$a和$b,以确定是将它们包括在交叉点中,还是排除它们。那么为什么返回-1、0或1而不是简单的布尔值呢 以下是我想要实现的一些(工作)功能,我只是好奇它为什么会这样工作。我认为原因在于PHP源代码usort和array\u uintersect以及其他类似的用户回调比较函数,即PHP\u array\u user\u compare xref:/PHP\u 5\u 3/ext/standard/array.c 568sta

在文档的注释中指出,回调函数必须返回-1($a<$b)、0($a===$b)或1($a>$b)

回调函数的目的是比较$a和$b,以确定是将它们包括在交叉点中,还是排除它们。那么为什么返回-1、0或1而不是简单的布尔值呢


以下是我想要实现的一些(工作)功能,我只是好奇它为什么会这样工作。

我认为原因在于PHP源代码
usort
array\u uintersect
以及其他类似的用户回调比较函数,即
PHP\u array\u user\u compare

xref:/PHP\u 5\u 3/ext/standard/array.c

568static int php_array_user_compare(const void *a, const void *b TSRMLS_DC) /* {{{ */
569{
570    Bucket *f;
571    Bucket *s;
572    zval **args[2];
573    zval *retval_ptr = NULL;
574
575    f = *((Bucket **) a);
576    s = *((Bucket **) b);
577
578    args[0] = (zval **) f->pData;
579    args[1] = (zval **) s->pData;
580
581    BG(user_compare_fci).param_count = 2;
582    BG(user_compare_fci).params = args;
583    BG(user_compare_fci).retval_ptr_ptr = &retval_ptr;
584    BG(user_compare_fci).no_separation = 0;
585    if (zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache) TSRMLS_CC) == SUCCESS && retval_ptr) {
586        long retval;
587
588        convert_to_long_ex(&retval_ptr);
589        retval = Z_LVAL_P(retval_ptr);
590        zval_ptr_dtor(&retval_ptr);
591        return retval < 0 ? -1 : retval > 0 ? 1 : 0;
592    } else {
593        return 0;
594    }
595}
如果您使用的是布尔值且需要进行转换,则只能给出
0
1

范例

var_dump((int) true); // 1
var_dump((int) false); // 0
这意味着您可能能够在intersect期间避开
boolean
,因为只有
$a===$b=0
是必需的,但对于
retval<0

只返回布尔值的接受回调的其他实现则不需要。 php函数不支持。
所以原因可能是php中的优化。您可以在引擎盖下检查此

是对C函数的调用
zend\u qsort

if (behavior == INTERSECT_NORMAL) {
    zend_qsort((void *) lists[i], hash->nNumOfElements, sizeof(Bucket *), intersect_data_compare_func TSRMLS_CC);
} else if (behavior & INTERSECT_ASSOC) { /* triggered also when INTERSECT_KEY */
    zend_qsort((void *) lists[i], hash->nNumOfElements, sizeof(Bucket *), intersect_key_compare_func TSRMLS_CC);
}
对这些关系非常敏感,因此它可以执行其算法的分区组件。与轴具有相同值的项目将放置在轴的相邻位置或任一侧


有趣的是,大于比较运算符
用于对象比较,这是一种未记录的行为。根据一条评论,PHP查看公共对象的值进行比较。这实际上是现在

值得一提的是,
array\u uintersect()
对数组输入的操作甚至比人们希望的更奇怪。人们期望调用
array\u uintersect($firstArray,$secondArray,function($a,$b){})
将导致
$firstArray
中的每个条目和
$secondArray
中的每个条目分别进行一次比较(在找到第一个交叉点后,对条目停止比较进行优化)。任何理智的人都会期望,
$firstArray
的每个条目都会进入回调的
$a
参数,而
$secondArray
的每个条目都会进入其
$b
参数

事实并非如此!信不信由你,php对回调函数的第一次调用将
$a
$b
都设置为
$firstArray
中的条目!您正在调用一个以数组的交集命名的函数,但该函数也会比较单个数组中的条目,而不仅仅是比较数组之间的条目。这真是让人麻木

因此,
array\u uintersect
不是以下块的替代品。用户要当心

$intersection = [];
foreach ($firstArray as $a) {
    foreach ($secondArray as $b) {
        if (user_compare_function($a, $b) === 0) {
            $intersection[] = $a;
            break;
        }
    }
}

但是为什么需要三个值呢?我认为这3个条件是用某种内部排序来考虑的:<代码> -1 ,<代码> 0 和<代码> 1 < /COD>实际上是典型的排序标准。抱歉,我没有考虑这个特殊情况。在这种情况下,只需要两个值:一个值是否存在于另一个数组中。排序函数确实需要知道一个值是否不同,因为它是大还是小。为了避免有两种语义不同的回调,它们只是让array_uintersect()使用与usort()相同的类型。也许它们只是想在数组排序函数方面保持一致。编辑:基本上是cleong说的;)bool
function myfunction($v1,$v2){if($v1===$v2)返回0;//if($v1>$v2)返回1;//取消注释以查看正确的结果,否则返回-1;}$a1=array(2,4,1)$a2=阵列(3,1,4);打印(数组接口($a1,$a2,“myfunction”)array\u uintersect()
会给出与上面代码不同的结果?
$intersection = [];
foreach ($firstArray as $a) {
    foreach ($secondArray as $b) {
        if (user_compare_function($a, $b) === 0) {
            $intersection[] = $a;
            break;
        }
    }
}