private function findConflict(
        ValidationContext $context,
        $parentFieldsAreMutuallyExclusive,
        $responseName,
        array $field1,
        array $field2
    ) {
        [$parentType1, $ast1, $def1] = $field1;
        [$parentType2, $ast2, $def2] = $field2;

        // If it is known that two fields could not possibly apply at the same
        // time, due to the parent types, then it is safe to permit them to diverge
        // in aliased field or arguments used as they will not present any ambiguity
        // by differing.
        // It is known that two parent types could never overlap if they are
        // different Object types. Interface or Union types might overlap - if not
        // in the current state of the schema, then perhaps in some future version,
        // thus may not safely diverge.
        $areMutuallyExclusive =
            $parentFieldsAreMutuallyExclusive ||
            (
                $parentType1 !== $parentType2 &&
                $parentType1 instanceof ObjectType &&
                $parentType2 instanceof ObjectType
            );

        // The return type for each field.
        $type1 = $def1 === null ? null : $def1->getType();
        $type2 = $def2 === null ? null : $def2->getType();

        if (! $areMutuallyExclusive) {
            // Two aliases must refer to the same field.
            $name1 = $ast1->name->value;
            $name2 = $ast2->name->value;
            if ($name1 !== $name2) {
                return [
                    [$responseName, sprintf('%s and %s are different fields', $name1, $name2)],
                    [$ast1],
                    [$ast2],
                ];
            }

            if (! $this->sameArguments($ast1->arguments ?: [], $ast2->arguments ?: [])) {
                return [
                    [$responseName, 'they have differing arguments'],
                    [$ast1],
                    [$ast2],
                ];
            }
        }

        if ($type1 && $type2 && $this->doTypesConflict($type1, $type2)) {
            return [
                [$responseName, sprintf('they return conflicting types %s and %s', $type1, $type2)],
                [$ast1],
                [$ast2],
            ];
        }

        // Collect and compare sub-fields. Use the same "visited fragment names" list
        // for both collections so fields in a fragment reference are never
        // compared to themselves.
        $selectionSet1 = $ast1->selectionSet;
        $selectionSet2 = $ast2->selectionSet;
        if ($selectionSet1 && $selectionSet2) {
            $conflicts = $this->findConflictsBetweenSubSelectionSets(
                $context,
                $areMutuallyExclusive,
                Type::getNamedType($type1),
                $selectionSet1,
                Type::getNamedType($type2),
                $selectionSet2
            );

            return $this->subfieldConflicts(
                $conflicts,
                $responseName,
                $ast1,
                $ast2
            );
        }

        return null;
    }
private function findConflict(
        ValidationContext $context,
        $parentFieldsAreMutuallyExclusive,
        $responseName,
        array $field1,
        array $field2
    ) {
        [$parentType1, $ast1, $def1] = $field1;
        [$parentType2, $ast2, $def2] = $field2;

        // If it is known that two fields could not possibly apply at the same
        // time, due to the parent types, then it is safe to permit them to diverge
        // in aliased field or arguments used as they will not present any ambiguity
        // by differing.
        // It is known that two parent types could never overlap if they are
        // different Object types. Interface or Union types might overlap - if not
        // in the current state of the schema, then perhaps in some future version,
        // thus may not safely diverge.
        $areMutuallyExclusive =
            $parentFieldsAreMutuallyExclusive ||
            (
                $parentType1 !== $parentType2 &&
                $parentType1 instanceof ObjectType &&
                $parentType2 instanceof ObjectType
            );

        // The return type for each field.
        $type1 = $def1 === null ? null : $def1->getType();
        $type2 = $def2 === null ? null : $def2->getType();

        if (! $areMutuallyExclusive) {
            // Two aliases must refer to the same field.
            $name1 = $ast1->name->value;
            $name2 = $ast2->name->value;
            if ($name1 !== $name2) {
                return [
                    [$responseName, sprintf('%s and %s are different fields', $name1, $name2)],
                    [$ast1],
                    [$ast2],
                ];
            }

            if (! $this->sameArguments($ast1->arguments ?: [], $ast2->arguments ?: [])) {
                return [
                    [$responseName, 'they have differing arguments'],
                    [$ast1],
                    [$ast2],
                ];
            }
        }

        if ($type1 && $type2 && $this->doTypesConflict($type1, $type2)) {
            return [
                [$responseName, sprintf('they return conflicting types %s and %s', $type1, $type2)],
                [$ast1],
                [$ast2],
            ];
        }

        // Collect and compare sub-fields. Use the same "visited fragment names" list
        // for both collections so fields in a fragment reference are never
        // compared to themselves.
        $selectionSet1 = $ast1->selectionSet;
        $selectionSet2 = $ast2->selectionSet;
        if ($selectionSet1 && $selectionSet2) {
            $conflicts = $this->findConflictsBetweenSubSelectionSets(
                $context,
                $areMutuallyExclusive,
                Type::getNamedType($type1),
                $selectionSet1,
                Type::getNamedType($type2),
                $selectionSet2
            );

            return $this->subfieldConflicts(
                $conflicts,
                $responseName,
                $ast1,
                $ast2
            );
        }

        return null;
    }
private function findConflict ( ValidationContext $ context , $ parentFieldsAreMutuallyExclusive , $ responseName , array $ field1 , array $ field2 ) { [ $ parentType1 , $ ast1 , $ def1 ] = $ field1 ; [ $ parentType2 , $ ast2 , $ def2 ] = $ field2 ; // If it is known that two fields could not possibly apply at the same // time, due to the parent types, then it is safe to permit them to diverge // in aliased field or arguments used as they will not present any ambiguity // by differing. // It is known that two parent types could never overlap if they are // different Object types. Interface or Union types might overlap - if not // in the current state of the schema, then perhaps in some future version, // thus may not safely diverge. $ areMutuallyExclusive = $ parentFieldsAreMutuallyExclusive || ( $ parentType1 !== $ parentType2 && $ parentType1 instanceof ObjectType && $ parentType2 instanceof ObjectType ) ; // The return type for each field. $ type1 = $ def1 === null ? null : $ def1 -> getType ( ) ; $ type2 = $ def2 === null ? null : $ def2 -> getType ( ) ; if ( ! $ areMutuallyExclusive ) { // Two aliases must refer to the same field. $ name1 = $ ast1 -> name -> value ; $ name2 = $ ast2 -> name -> value ; if ( $ name1 !== $ name2 ) { return [ [ $ responseName , sprintf ( '%s and %s are different fields' , $ name1 , $ name2 ) ] , [ $ ast1 ] , [ $ ast2 ] , ] ; } if ( ! $ this -> sameArguments ( $ ast1 -> arguments ? : [ ] , $ ast2 -> arguments ? : [ ] ) ) { return [ [ $ responseName , 'they have differing arguments' ] , [ $ ast1 ] , [ $ ast2 ] , ] ; } } if ( $ type1 && $ type2 && $ this -> doTypesConflict ( $ type1 , $ type2 ) ) { return [ [ $ responseName , sprintf ( 'they return conflicting types %s and %s' , $ type1 , $ type2 ) ] , [ $ ast1 ] , [ $ ast2 ] , ] ; } // Collect and compare sub-fields. Use the same "visited fragment names" list // for both collections so fields in a fragment reference are never // compared to themselves. $ selectionSet1 = $ ast1 -> selectionSet ; $ selectionSet2 = $ ast2 -> selectionSet ; if ( $ selectionSet1 && $ selectionSet2 ) { $ conflicts = $ this -> findConflictsBetweenSubSelectionSets ( $ context , $ areMutuallyExclusive , Type :: getNamedType ( $ type1 ) , $ selectionSet1 , Type :: getNamedType ( $ type2 ) , $ selectionSet2 ) ; return $ this -> subfieldConflicts ( $ conflicts , $ responseName , $ ast1 , $ ast2 ) ; } return null ; }
Determines if there is a conflict between two particular fields, including
comparing their sub-fields.

@param bool    $parentFieldsAreMutuallyExclusive
@param string  $responseName
@param mixed[] $field1
@param mixed[] $field2

@return mixed[]|null
Determines if there is a conflict between two particular fields including comparing their sub - fields .