在array_uintersect的文档评论中注意到,回调函数必须返回-1($ a< $ b),0($ a === $ b)或1($ a> $ b)
回调函数的目的是比较$ a和$ b以确定是否将它们包含在交集中,或者将它们排除。那么为什么要返回-1,0或1而不是简单的布尔值?
这是我想要实现的一些(工作)example code,我只是好奇为什么它会这样。
答案 0 :(得分:4)
值得一提的是,array_uintersect()
在您的阵列输入上奇怪地运行 more ,而不是希望的。一个人希望调用array_uintersect($firstArray, $secondArray, function ($a, $b) {})
将导致来自$firstArray
的每个条目和来自$secondArray
的每个条目进行一次比较(在找到第一个交集之后优化停止比较条目)。任何理智的人都会期望$firstArray
的每个条目都会出现在回调的$a
参数中,并且$secondArray
的每个条目都会落入其$b
参数中。< / p>
这是不的情况!信不信由你,php首次拨打你的回叫电话的$a
和$b
都设置为来自$firstArray
的条目!您正在调用以数组交集命名的函数,但该函数还会比较各个数组中的条目,而不是简单地比较数组。真的很麻烦。
因此,array_uintersect
不是以下块的替代品。用户要小心。
$intersection = [];
foreach ($firstArray as $a) {
foreach ($secondArray as $b) {
if (user_compare_function($a, $b) === 0) {
$intersection[] = $a;
break;
}
}
}
答案 1 :(得分:1)
我认为原因在于PHP源usort
和array_uintersect
以及其他类似的用户回调比较函数php_array_user_compare
xref: /PHP_5_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}
这使用retval
,如果你看
retval < 0 ? -1 : retval > 0 ? 1 : 0
如果您使用布尔值并且需要转换,则只能提供0
或1
示例
var_dump((int) true); // 1
var_dump((int) false); // 0
这意味着您可以在交叉期间使用boolean
,因为只有$a === $b = 0
需要retval < 0
而不是其他{{1}}
答案 2 :(得分:1)
pear replacement接受回调,只返回一个布尔值。 php函数没有。 所以原因可能是php中的优化。你可以查看here
答案 3 :(得分:1)
在幕后,是对C函数zend_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);
}
Quicksort对这些关系很敏感,因此它可以执行其算法的分区组件。与 pivot 具有相同值的项目放在 pivot 的旁边和两侧。
有趣的是,大于比较运算符>
适用于对象比较,这是一种无证件行为。根据一条评论,PHP会查看此对比的公共对象的值。这实际上是a discussion point on the internals list现在!