2012-02-27 6 views
5

Прежде всего, я должен упомянуть, что я выкопал документы вручную и php и не нашел ответа. Вот код, я использую:Поведение array_diff_uassoc непонятно

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'); 

То, что я думал, array_diff_uassoc будет сравнить все значения этих двух массивов, и если значения существует, то будет работать ключ сравнения. И выход из этого кода:

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 

Итак, прежде всего, почему некоторые пары (1: 0 или 3: 1) дублируются? Означает ли это, что функция забыла, что она уже сравнила эти предметы? Я думал, что он будет сравнивать все пары с равным значением, но я не вижу его в выходе. Я что-то упускаю?

Вопрос: что такое точное поведение этой функции в терминах порядка сравнения, и почему я вижу это дубликаты? (Мой PHP версия, если это поможет это: PHP Version 5.3.6-13ubuntu3.6)

Я действительно путают, и ожидая какого-то хорошее объяснение этого ...

+1

Вы должны, вероятно, использовать строгое сравнение!== not == в функции сравнения. –

+0

Сравнение в этом случае не является большой честью. Мне интересно, почему «эхо» печатает такие результаты при сравнении. И 'echo' запускается перед сравнением, поэтому не имеет значения, насколько он строг или нет. – Karol

+0

Я хотел бы написать этот код: я хочу только эти элементы, которые не находятся во втором массиве ($ a [0]), и если они находятся во втором массиве, я хочу, чтобы эти элементы имели один и тот же ключ (индекс) ... Так что, конечно, функция должна возвращать только $ a [0] – Karol

ответ

0

из op'scomment что

Я хочу только эти элементы, которые не во втором массиве ($ а [0])

не может использовать array_diff($a, $b);? она возвращает

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

В противном случае,

The documentation состояния, что:

функция

Сравнение должна возвращать целое число меньше, равно или больше нуля, если первый аргумент считаются соответственно меньше, равно или больше вторых.

Как я понимаю, это означает, что функция compare() должна быть больше, как это:

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

Однако даже при такой коррекции, это очень странно сравнивать результаты:

 
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 

Я спросил об этом another question, так как он вышел из сферы ответа.

0

Я думаю, вы пропустили раздел возвращаемого значения.

Возвращает массив, содержащий все записи из массива, которые не присутствуют ни в одном из других массивов.

ключи сравнения используются для сравнения.

В тексте отсутствует то, что сравнение осуществляется только ассоциативно.Это означает, что любые автоматически объявленные или определяемые пользователем числовые ключи вводятся как строки не целые.

Так с

$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); // 

Поскольку $ один горячий => d не соответствует $ два 0 => d на ассоциативном уровне $ один горячий => d возвращается.

Из-за причуды PHP при сопоставлении типов строк и целочисленных данных пользовательская функция может использоваться для улучшения сравнения с помощью более сильных операций сравнения, таких как ===.

Это помогает в ситуациях, когда тип неоднозначный '0' => d и 0 => d может выглядеть похожим, но пока вы не говорите об этом в своем коде.

К счастью, намекающий тип подходит к PHP7, чтобы избавить нас от этого типа странной конструкции и нечеткой документации.

Я добавляю это из своего комментария, потому что он относится к вашему пониманию того, какие конструкции php лучше всего использовать в вашем случае. Мой комментарий:

Я не уверен, что так как если ($ а = $ Ь!) {В коде является проблема. Поскольку они ошибочно используют равенство, когда они должны быть с использованием идентичных операторов! ==. И они используют числовые ключи в конструкции , предназначенной для ассоциативных ключей. они, вероятно, также не знают о array_udiff, что лучше соответствует данным, связанным с данными

+0

довольно ясно, что op очень хорошо осведомлен о том, что вы здесь говорите. –

+1

Я не уверен в этом, так как if ($ a! = $ B) {в их коде есть проблема. Поскольку они ошибочно используют равенство, когда они должны использовать одинаковые операторы. И они используют числовые ключи в конструкции, предназначенной для ассоциативных ключей. они, вероятно, также не знают о array_udiff, который лучше подходит для данных, связанных с –

0

Это несколько интригует. Я посмотрел последний источник PHP на github (который написан на C++, как вы, наверное, знаете), и попытался понять это. (https://github.com/php/php-src/blob/master/ext/standard/array.c)

Быстрый поиск показал мне, что рассматриваемая функция объявлена ​​в строке 4308

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

Так что показывает, что фактическая работа выполняется с помощью функции php_array_diff, что можно найти в том же файл в строке 3938. Это немного длиннее, чтобы вставить его здесь, 265 строк, если быть точным, но вы можете найти его, если хотите.

В тот момент, когда я сдался. У меня нет опыта в C вообще, и я опаздываю, и я устал, чтобы попытаться понять это. Я полагаю, что сначала выполняется сравнение ключей, так как это, вероятно, более показательно, чем сравнение значений, но это всего лишь предположение. Во всяком случае, вероятно, есть веская причина, почему они делают это так, как делают.

Все это просто длинный введение сказать, почему вы хотите, чтобы положить echo внутри compare функции в первую очередь? Целью array_diff_uassoc является выход функции. Вы не должны полагаться на то, как обрабатывает его синтаксический анализатор. Если завтра они решат изменить внутреннюю работу этой C-функции, то есть. сначала сравните значение, вы получите совершенно другой результат.

Может быть, вы могли бы использовать эту функцию замены, что написано в PHP: http://pear.php.net/reference/PHP_Compat-1.6.0a2/__filesource/fsource_PHP_Compat__PHP_Compat-1.6.0a2CompatFunctionarray_diff_uassoc.php.html

Таким образом, вы можете полагаться на поведение не изменится, и у вас есть полный контроль внутренних работ ...

+0

. Это строка 3631 вашей ссылки github: '} else if (behavior & INTERSECT_ASSOC && key_compare_type == INTERSECT_COMP_KEY_USER) {'. строка 3321 - пустая строка. Понятно, что эхо не сделано для функциональности, а скорее для тестирования, и оно показывает странные результаты. –

+1

@ FélixGagnon-Grenier извините, я испортил номера строк там (я действительно загрузил источник из php.net, и только позже выяснил, что источник был на Github. Думал, что было бы проще связать там, но забыл проверить номера строк. Ctrl/Cmd + F привезли бы вас туда) Обновлено сейчас, но поскольку ссылка указывает на текущего мастера, она может снова измениться в будущем. – Pevara

+1

Пункт моего ответа состоит в том, что вы должны учитывать эту функцию как черный ящик и не полагаться на его внутренние работы. Это все о API и выходе, теперь * как * функция получает этот результат, так как это может измениться в будущем. – Pevara