Comportamiento de array_diff_uassoc no claro

En primer lugar, debo mencionar que busqué en manuales y php docs y no encontré una respuesta. Aquí hay un código que uso:

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
"); 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, 'compare');

Lo que pensé, array_diff_uassoc comparará todos los valores de estas dos matrices, y si existen valores, entonces ejecutará la comparación de claves. Y el resultado de este código es:

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

Entonces, ¿en primer lugar por qué algunos pares (1: 0 o 3: 1) están duplicados? ¿Significa que la función olvidó que ya había comparado estos elementos? Pensé que compararía todos los pares iguales por valor, pero no lo veo en el resultado. ¿Me estoy perdiendo de algo?

Entonces la pregunta es: ¿cuál es el comportamiento exacto de esta función en términos de orden de comparación, y por qué veo esto duplicados? (mi versión de PHP, si me sirve es: PHP Version 5.3.6-13ubuntu3.6)

Estoy realmente confundido y esperando una buena explicación de eso …

Creo que te perdiste la sección de valor de retorno.

Devuelve una matriz que contiene todas las entradas de la matriz 1 que no están presentes en ninguna de las otras matrices.

las teclas de matriz se utilizan en la comparación.

Lo que falta en el texto es que la comparación solo se hace asociativamente. Esto significa que cualquier clave numérica declarada automáticamente o definida por el usuario se escribe como cadenas, no como enteros.

Entonces con

 $one = array(a,b,c,'hot'=>d); // d has no match and will be returned as array and go to the function alone $two = array(a,b,c,d,e,f); // 

Como $ one hot => d no coincide con $ two 0 => d en un nivel asociativo, se devuelve $ one hot => d.

Debido a la peculiaridad PHP de las comparaciones de tipo de datos de cadena y entero, se puede usar una función definida por el usuario para mejorar la comparación mediante el uso de operaciones de comparación más fuertes como ===.

Esto ayuda en situaciones donde el tipo es ambiguo ‘0’ => d y 0 => d puede parecer similar pero no lo son hasta que lo diga en su código.

Afortunadamente, se insinúa que PHP7 se va a despojar de este tipo de construcciones extrañas y de documentación poco clara.

Estoy agregando esto de mi comentario porque se refiere a su comprensión de qué construcciones php se usan mejor en su caso. Mi comentario:

No estoy tan seguro de eso ya que si ($ a! = $ B) {en su código es un problema. ¡Ya que están usando equitativamente la igualdad cuando deberían usar operadores idénticos! ==. Y están usando claves numéricas en una construcción diseñada para claves asociativas. es probable que tampoco tengan conocimiento de array_udiff, que es una mejor coincidencia para los datos involucrados

Esto es de alguna manera intrigante. Busqué la última fuente de PHP en github (que está escrita en C ++ como probablemente sabrá) e intenté darle sentido. ( https://github.com/php/php-src/blob/master/ext/standard/array.c )

Una búsqueda rápida me mostró que la función en cuestión está declarada en la línea 4308

 PHP_FUNCTION(array_diff_uassoc) { php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_ASSOC, DIFF_COMP_DATA_INTERNAL, DIFF_COMP_KEY_USER); } 

Así que eso muestra que el trabajo real lo realiza la función php_array_diff , que se puede encontrar en ese mismo archivo en la línea 3938. Es un poco largo pegarlo aquí, 265 líneas para ser exactos, pero puede buscarlo si lo desea .

Ese es el punto donde me di por vencido. No tengo experiencia en C en absoluto, y es demasiado tarde y estoy cansado de intentar darle sentido. Supongo que la comparación de claves se hace primero, ya que es más probable que luego comparando los valores, pero eso es solo una suposición. De todos modos, es probable que haya una buena razón por la que lo hacen de la manera en que lo hacen.

Todo eso es solo una introducción larga para decir, ¿por qué querrías poner un echo dentro de tu función de compare en primer lugar ? El objective de array_diff_uassoc es la salida de la función. No debe confiar en cómo lo maneja el analizador. Si deciden mañana cambiar el funcionamiento interno de esa función C a ie. Haga la comparación de valores primero, obtendrá un resultado completamente diferente.

Quizás podría usar esta función de reemplazo que está escrita en php: http://pear.php.net/reference/PHP_Compat-1.6.0a2/__filesource/fsource_PHP_Compat__PHP_Compat-1.6.0a2CompatFunctionarray_diff_uassoc.php.html

De esa manera puede confiar en que el comportamiento no cambie, y usted tiene el control total del funcionamiento interno …

del comentario de op que

Solo quiero estos elementos que no están en la segunda matriz ($ a [0])

no puedes usar array_diff($a, $b); ? vuelve

 array(1) { [0]=> int(5) } 

de otra manera,

La documentación establece que:

La función de comparación debe devolver un número entero menor, igual o mayor que cero si el primer argumento se considera que es, respectivamente, menor, igual o mayor que el segundo.

Según lo entiendo, eso significa que la función compare() debería ser más como esta:

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

Sin embargo, incluso con esta corrección, tiene resultados de comparación muy extraños:

 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

Hice otra pregunta sobre esto, ya que estaba saliendo del scope de una respuesta.