2012-02-27 9 views
5

Prima di tutto devo menzionare che ho inserito documenti manuali e php e non ho trovato risposta. Ecco un codice che uso:Comportamento di array_diff_uassoc non chiaro

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<br/>"); 
    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'); 

Quello che ho pensato, array_diff_uassoc comparerà i valori di questi due array, e se i valori esiste, allora verrà eseguito il confronto chiave. E l'uscita di questo codice è:

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 

Quindi prima di tutto perché alcune coppie (1: 0 o 3: 1) sono duplicati? Significa che la funzione ha dimenticato che ha già confrontato questi elementi? Ho pensato che avrebbe confrontato tutte le coppie uguali per valore, ma non l'ho visto in output. Mi sto perdendo qualcosa?

Quindi la domanda è: qual è il comportamento esatto di questa funzione in termini di ordine di confronto e perché vedo questi duplicati? (La mia versione di PHP, se aiuta è: Versione PHP 5.3.6-13ubuntu3.6)

Sono molto confuso, e in attesa di qualche buona spiegazione di esso ...

+1

Probabilmente dovresti usare un confronto rigoroso!== non == nella funzione di confronto. –

+0

Il confronto in sé non è un grosso problema per essere onesti in questo caso. Mi chiedo perché 'echo' sta stampando tali risultati durante il confronto. E 'echo' viene attivato prima del confronto, quindi non importa se sia rigoroso o meno. – Karol

+0

Quello che volevo ottenere scrivendo questo codice è: voglio solo questi elementi che non sono nel secondo array ($ a [0]), e se sono nel secondo array, voglio questi elementi che hanno la stessa chiave (indice) ... Quindi ovviamente la funzione dovrebbe restituire solo $ a [0] – Karol

risposta

0

da op'scomment che

voglio solo questi elementi che non sono in secondo array ($ a [0])

può non usare array_diff($a, $b);? restituisce

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

altrimenti,

The documentation stabilisce che:

funzione

Il confronto deve restituire un intero minore, uguale o superiore a zero se il primo argomento è considerato come rispettivamente inferiore, uguale o superiore a il secondo.

A quanto mi risulta, il che significa che la funzione compare() dovrebbe essere più simile a questo:

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

Tuttavia, anche con questa correzione, è molto strano confronta i risultati:

 
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 

Ho chiesto a another question di farlo perché stava uscendo dall'ambito di una risposta.

0

Penso che abbiate perso la sezione del valore di ritorno.

Restituisce una matrice contenente tutte le voci da matrice1 che non sono presenti in nessuno degli altri array.

le chiavi di matrice vengono utilizzate nel confronto.

Ciò che manca nel testo è che il confronto è fatto solo in modo associativo.Ciò significa che tutte le chiavi numeriche definite automaticamente o definite dall'utente vengono digitate come stringhe e non come numeri interi.

Quindi, 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); // 

Perché $ caldo uno => d non corrisponde due $ 0 => d a livello associativo $ caldo uno => D viene restituito.

A causa del capriccio PHP di confronto tra tipi di dati stringa e intero, è possibile utilizzare una funzione definita dall'utente per migliorare il confronto utilizzando operazioni di confronto più forti come ===.

Questo aiuta in situazioni in cui il tipo è ambiguo '0' => d e 0 => d potrebbe sembrare simile ma non lo è fino a quando non lo dici nel tuo codice.

Fortunatamente il tipo di suggerimento è in arrivo su PHP7 per liberarci di questo tipo di costrutto strano e di documentazione poco chiara.

Aggiungo questo dal mio commento perché riguarda la comprensione di quali costrutti php sono maggiormente utilizzati nel tuo caso. Il mio commento:

Non ne sono così sicuro poiché se ($ a! = $ B) {nel loro codice è un problema . Dal momento che usano erroneamente l'uguaglianza quando dovrebbero essere utilizzando operatori identici! ==. E stanno usando i tasti numerici in un costrutto progettato per le chiavi associative. probabilmente sono anche inconsapevoli di array_udiff che corrisponde meglio ai dati coinvolti

+0

è piuttosto chiaro op è molto consapevole di ciò che stai dicendo qui. –

+1

Non ne sono così sicuro poiché se ($ a! = $ B) {nel loro codice è un problema. Dal momento che usano erroneamente l'uguaglianza quando dovrebbero usare operatori identici. E stanno usando le chiavi numeriche in un costrutto progettato per le chiavi associative. probabilmente sono anche inconsapevoli di array_udiff che una corrispondenza migliore per i dati coinvolti è –

0

Questo è davvero un po 'intrigante. Ho cercato l'ultima fonte di PHP su github (che è scritto in C++ come probabilmente sapete) e ho cercato di dare un senso a ciò. (https://github.com/php/php-src/blob/master/ext/standard/array.c)

Una rapida ricerca mi ha mostrato che la funzione in questione è dichiarata on line 4308

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

In modo che dimostra che il lavoro effettivo è fatto dalla funzione php_array_diff, che possono essere trovati in quello stesso file on line 3938. È un po 'lungo incollarlo qui, 265 righe per essere esatte, ma puoi cercarlo se vuoi.

Questo è il punto in cui ho rinunciato. Non ho esperienza in C qualunque, ed è troppo tardi e sono stanco di cercare di dare un senso a questo. Suppongo che il confronto delle chiavi sia fatto prima, poiché probabilmente è più performante rispetto ai valori, ma è solo un'ipotesi. Ad ogni modo, c'è probabilmente una buona ragione per cui lo fanno nel modo in cui lo fanno.

Tutto questo è solo una lunga introduzione per dire, perché si vuole porre echo all'interno vostra funzione compare in primo luogo? L'obiettivo di array_diff_uassoc è l'output della funzione. Non dovresti fare affidamento su come il parser lo gestisce. Se decidono domani di cambiare il funzionamento interno di quella funzione C per es. fai prima il confronto dei valori, otterrai un risultato completamente diverso.

Forse si potrebbe utilizzare questa funzione di sostituzione che è scritto in PHP: http://pear.php.net/reference/PHP_Compat-1.6.0a2/__filesource/fsource_PHP_Compat__PHP_Compat-1.6.0a2CompatFunctionarray_diff_uassoc.php.html

In questo modo è possibile affidamento sul comportamento non cambia, e si ha il pieno controllo del funzionamento interno ...

+0

questa è la riga 3631 del tuo link github: '} else if (comportamento & INTERSECT_ASSOC && key_compare_type == INTERSECT_COMP_KEY_USER) {'. la riga 3321 è una riga vuota. È abbastanza chiaro che l'eco non è fatto per funzionalità, ma piuttosto per test, e mostra risultati strani. –

+1

@ FélixGagnon-Grenier scusate, ho incasinato i numeri di riga lì (ho effettivamente scaricato la fonte da php.net e solo successivamente ho scoperto che la fonte era anche su Github. Pensavo che sarebbe stato più facile collegarvi lì ma ho dimenticato di controllare il numeri di linea. Ctrl/Cmd + F ti avrebbe portato lì comunque) Aggiornato ora, ma poiché il link punta al master attuale è probabile che cambi di nuovo in futuro. – Pevara

+1

Il punto della mia risposta è che dovresti considerare quella funzione una scatola nera e non fare affidamento sui suoi meccanismi interni. Riguarda l'API e l'output, ora * come * la funzione raggiunge quel risultato, poiché potrebbe cambiare in futuro. – Pevara

Problemi correlati