Por que array_diff_uassoc compara as chaves cujo valor não corresponde

Acabei de ler essa pergunta sobre o comportamento estranho do php, e mesmo que eu pudesse pesquisar um pouco mais, não estou perto de entendê-lo.

Eu suponho que o leitor tenha lido a pergunta original e está ciente do bloco de código e da amostra do OP, mas em suma, o OP está tentando comparar essas duas matrizes e, embora o resultado seja bom, a function de comparação parece ser chamada de forma errática:

$chomik = new chomik('a'); $a = array(5, $chomik, $chomik, $chomik); $b = array($chomik, 'b', 'c', 'd'); array_diff_uassoc($a, $b, 'compare'); 

A documentação é um pouco obscura … mas afirma que:

A function de comparação deve retornar um número inteiro menor do que, igual ou maior do que zero, se o primeiro argumento for considerado menor que, igual ou maior que o segundo.

Como eu entendo, isso significa que a function compare() deve ser mais assim:

 function compare($a, $b) { echo("$a : $b
"); if($a === $b) return 0; else if ($a > $b) return 1; else return -1; }

No entanto, isso ainda dá resultados muito estranhos, com ainda mais “duplicatas”

 1: 0
 1: 2
 3: 1
 2: 1
 3: 2
 1: 0
 1: 2
 3: 1
 2: 1
 3: 2
 0: 0
 1: 0
 1: 1
 2: 0
 2: 1
 2: 2
 3: 0
 3: 1
 3: 2
 3: 3

confrontado com muitas dúvidas, leio a function compat php e a parte em que o cheque realmente acontece é interessante:

 foreach ($args[0] as $k => $v) { for ($i = 1; $i  $vv) { if ($v == $vv) { // compare keys only if value are the same $compare = call_user_func_array($compare_func, array($k, $kk)); if ($compare == 0) { continue 3; // value should not be added to the result } } } } $result[$k] = $v; } 

aqui está a fonte real (por comentário )

A forma como este código executa a function de comparação não deve ser a saída do resultado que vemos. Foreach não é capaz de mover-se para a frente e para trás nas teclas (AFAIK ???), como parece ser o caso na ordem da primeira chave aqui:

 1: 2
 3: 1
 2: 1

Além disso, não deve verificar as chaves se o valor não corresponder, então por que tudo isso está marcado:

 1: 2
 3: 1
 2: 1
 3: 2
 etc ...

Como o foreach mais alto () no código fonte é encurralado para frente e para trás através das teclas ?!

Por que as chaves cujos valores não correspondem ainda são comparadas?

Na verdade, os loops continuam sendo executados mesmo quando eles continue d?

Este é um exemplo de concorrência? pode chamar_user_func_array de alguma forma ser lançado e realmente executar o echo("$a : $b
");
da function de comparação não na mesma ordem em que foram “lançados” ??

Eu acredito que você identificou um bug, meu amigo. Eu apenas corri o código na pergunta que você referenciou, e com certeza, comparou chaves para valores que não eram os mesmos. No entanto, eu queria testar se o código-fonte em si continha o erro, então eu adicionei a fonte oficial para array_diff_uassoc isso para o topo do seu código, dentro do meu próprio namespace:

  $v) { for ($i = 1; $i < $array_count; $i++) { foreach ($args[$i] as $kk => $vv) { if ($v == $vv) { // echo ("$v\n"); // echo ("$vv\n"); // echo ("$k\n"); // echo ("$kk\n"); // die(); $compare = call_user_func_array($compare_func, array($k, $kk)); if ($compare == 0) { continue 3; } } } } $result[$k] = $v; } return $result; } class chomik { public $state = 'normal'; public $name = 'no name'; public function __construct($name) { $this->name = $name; } public function __toString() { return $this->name . " - " . $this->state; } } function compare($a, $b) { echo("$a : $b\n"); if($a != $b) { return 0; } else return 1; } $chomik = new chomik('a'); $a = array(5, $chomik, $chomik, $chomik); $b = array($chomik, 'b', 'c', 'd'); array_diff_uassoc($a, $b, 'mine\compare'); 

Desta vez, comparou apenas chaves para valores iguais:

 1 : 0 2 : 0 3 : 0 

Estranho, né?

A partir deste comentário de powerlord :

A julgar pelo fato de que a function de comparação personalizada pede que você retornar -1; 0; ou 1, parece que está fazendo um tipo antes ou ao mesmo tempo que uma comparação entre os dois arrays.

Fui encorajado a ir e ler a fonte real php_array_diff() , a function registrada para array_diff_uassoc() , e descobriu que ela usa a function de comparação muitas vezes, o que interpretei erroneamente como foreach indo e voltando para trás e para trás através das chaves.


Como o foreach mais alto () no código fonte é encurralado para frente e para trás através das teclas ?!

não. É só que a function fornecida pelo usuário

 diff_data_compare_func = php_array_user_compare; 

é usado várias vezes para classificar e avaliar os dados.

 [...] zend_sort((void *) lists[i], hash->nNumOfElements, sizeof(Bucket), diff_data_compare_func, (swap_func_t)zend_hash_bucket_swap); [...] while (Z_TYPE(ptrs[i]->val) != IS_UNDEF && (0 < (c = diff_data_compare_func(ptrs[0], ptrs[i])))) { [...] if (diff_data_compare_func(ptrs[0], ptr) != 0) { [...] 

Por que as chaves cujos valores não correspondem ainda são comparadas?

É verdade que o código de perigo compatível publicado na pergunta sugere que, se o valor não corresponder, a function de comparação não deve ser executada, mas php_array_diff() atua de forma diferente.


Os ciclos foreach realmente continuam executando mesmo quando eles continuaram? Este é um exemplo de concorrência?

Absurdo. Se eu fosse você, eu iria editar isso.