src/Utils/Value.php
public static function coerceValue($value, InputType $type, $blameNode = null, ?array $path = null)
    {
        if ($type instanceof NonNull) {
            if ($value === null) {
                return self::ofErrors([
                    self::coercionError(
                        sprintf('Expected non-nullable type %s not to be null', $type),
                        $blameNode,
                        $path
                    ),
                ]);
            }

            return self::coerceValue($value, $type->getWrappedType(), $blameNode, $path);
        }

        if ($value === null) {
            // Explicitly return the value null.
            return self::ofValue(null);
        }

        if ($type instanceof ScalarType) {
            // Scalars determine if a value is valid via parseValue(), which can
            // throw to indicate failure. If it throws, maintain a reference to
            // the original error.
            try {
                return self::ofValue($type->parseValue($value));
            } catch (Exception $error) {
                return self::ofErrors([
                    self::coercionError(
                        sprintf('Expected type %s', $type->name),
                        $blameNode,
                        $path,
                        $error->getMessage(),
                        $error
                    ),
                ]);
            } catch (Throwable $error) {
                return self::ofErrors([
                    self::coercionError(
                        sprintf('Expected type %s', $type->name),
                        $blameNode,
                        $path,
                        $error->getMessage(),
                        $error
                    ),
                ]);
            }
        }

        if ($type instanceof EnumType) {
            if (is_string($value)) {
                $enumValue = $type->getValue($value);
                if ($enumValue) {
                    return self::ofValue($enumValue->value);
                }
            }

            $suggestions = Utils::suggestionList(
                Utils::printSafe($value),
                array_map(
                    static function ($enumValue) {
                        return $enumValue->name;
                    },
                    $type->getValues()
                )
            );

            $didYouMean = $suggestions
                ? 'did you mean ' . Utils::orList($suggestions) . '?'
                : null;

            return self::ofErrors([
                self::coercionError(
                    sprintf('Expected type %s', $type->name),
                    $blameNode,
                    $path,
                    $didYouMean
                ),
            ]);
        }

        if ($type instanceof ListOfType) {
            $itemType = $type->getWrappedType();
            if (is_array($value) || $value instanceof Traversable) {
                $errors       = [];
                $coercedValue = [];
                foreach ($value as $index => $itemValue) {
                    $coercedItem = self::coerceValue(
                        $itemValue,
                        $itemType,
                        $blameNode,
                        self::atPath($path, $index)
                    );
                    if ($coercedItem['errors']) {
                        $errors = self::add($errors, $coercedItem['errors']);
                    } else {
                        $coercedValue[] = $coercedItem['value'];
                    }
                }

                return $errors ? self::ofErrors($errors) : self::ofValue($coercedValue);
            }
            // Lists accept a non-list value as a list of one.
            $coercedItem = self::coerceValue($value, $itemType, $blameNode);

            return $coercedItem['errors'] ? $coercedItem : self::ofValue([$coercedItem['value']]);
        }

        if ($type instanceof InputObjectType) {
            if (! is_object($value) && ! is_array($value) && ! $value instanceof Traversable) {
                return self::ofErrors([
                    self::coercionError(
                        sprintf('Expected type %s to be an object', $type->name),
                        $blameNode,
                        $path
                    ),
                ]);
            }

            $errors       = [];
            $coercedValue = [];
            $fields       = $type->getFields();
            foreach ($fields as $fieldName => $field) {
                if (array_key_exists($fieldName, $value)) {
                    $fieldValue   = $value[$fieldName];
                    $coercedField = self::coerceValue(
                        $fieldValue,
                        $field->getType(),
                        $blameNode,
                        self::atPath($path, $fieldName)
                    );
                    if ($coercedField['errors']) {
                        $errors = self::add($errors, $coercedField['errors']);
                    } else {
                        $coercedValue[$fieldName] = $coercedField['value'];
                    }
                } elseif ($field->defaultValueExists()) {
                    $coercedValue[$fieldName] = $field->defaultValue;
                } elseif ($field->getType() instanceof NonNull) {
                    $fieldPath = self::printPath(self::atPath($path, $fieldName));
                    $errors    = self::add(
                        $errors,
                        self::coercionError(
                            sprintf(
                                'Field %s of required type %s was not provided',
                                $fieldPath,
                                $field->type->toString()
                            ),
                            $blameNode
                        )
                    );
                }
            }

            // Ensure every provided field is defined.
            foreach ($value as $fieldName => $field) {
                if (array_key_exists($fieldName, $fields)) {
                    continue;
                }

                $suggestions = Utils::suggestionList(
                    $fieldName,
                    array_keys($fields)
                );
                $didYouMean  = $suggestions
                    ? 'did you mean ' . Utils::orList($suggestions) . '?'
                    : null;
                $errors      = self::add(
                    $errors,
                    self::coercionError(
                        sprintf('Field "%s" is not defined by type %s', $fieldName, $type->name),
                        $blameNode,
                        $path,
                        $didYouMean
                    )
                );
            }

            return $errors ? self::ofErrors($errors) : self::ofValue($coercedValue);
        }

        throw new Error(sprintf('Unexpected type %s', $type->name));
    }
public static function coerceValue($value, InputType $type, $blameNode = null, ?array $path = null)
    {
        if ($type instanceof NonNull) {
            if ($value === null) {
                return self::ofErrors([
                    self::coercionError(
                        sprintf('Expected non-nullable type %s not to be null', $type),
                        $blameNode,
                        $path
                    ),
                ]);
            }

            return self::coerceValue($value, $type->getWrappedType(), $blameNode, $path);
        }

        if ($value === null) {
            // Explicitly return the value null.
            return self::ofValue(null);
        }

        if ($type instanceof ScalarType) {
            // Scalars determine if a value is valid via parseValue(), which can
            // throw to indicate failure. If it throws, maintain a reference to
            // the original error.
            try {
                return self::ofValue($type->parseValue($value));
            } catch (Exception $error) {
                return self::ofErrors([
                    self::coercionError(
                        sprintf('Expected type %s', $type->name),
                        $blameNode,
                        $path,
                        $error->getMessage(),
                        $error
                    ),
                ]);
            } catch (Throwable $error) {
                return self::ofErrors([
                    self::coercionError(
                        sprintf('Expected type %s', $type->name),
                        $blameNode,
                        $path,
                        $error->getMessage(),
                        $error
                    ),
                ]);
            }
        }

        if ($type instanceof EnumType) {
            if (is_string($value)) {
                $enumValue = $type->getValue($value);
                if ($enumValue) {
                    return self::ofValue($enumValue->value);
                }
            }

            $suggestions = Utils::suggestionList(
                Utils::printSafe($value),
                array_map(
                    static function ($enumValue) {
                        return $enumValue->name;
                    },
                    $type->getValues()
                )
            );

            $didYouMean = $suggestions
                ? 'did you mean ' . Utils::orList($suggestions) . '?'
                : null;

            return self::ofErrors([
                self::coercionError(
                    sprintf('Expected type %s', $type->name),
                    $blameNode,
                    $path,
                    $didYouMean
                ),
            ]);
        }

        if ($type instanceof ListOfType) {
            $itemType = $type->getWrappedType();
            if (is_array($value) || $value instanceof Traversable) {
                $errors       = [];
                $coercedValue = [];
                foreach ($value as $index => $itemValue) {
                    $coercedItem = self::coerceValue(
                        $itemValue,
                        $itemType,
                        $blameNode,
                        self::atPath($path, $index)
                    );
                    if ($coercedItem['errors']) {
                        $errors = self::add($errors, $coercedItem['errors']);
                    } else {
                        $coercedValue[] = $coercedItem['value'];
                    }
                }

                return $errors ? self::ofErrors($errors) : self::ofValue($coercedValue);
            }
            // Lists accept a non-list value as a list of one.
            $coercedItem = self::coerceValue($value, $itemType, $blameNode);

            return $coercedItem['errors'] ? $coercedItem : self::ofValue([$coercedItem['value']]);
        }

        if ($type instanceof InputObjectType) {
            if (! is_object($value) && ! is_array($value) && ! $value instanceof Traversable) {
                return self::ofErrors([
                    self::coercionError(
                        sprintf('Expected type %s to be an object', $type->name),
                        $blameNode,
                        $path
                    ),
                ]);
            }

            $errors       = [];
            $coercedValue = [];
            $fields       = $type->getFields();
            foreach ($fields as $fieldName => $field) {
                if (array_key_exists($fieldName, $value)) {
                    $fieldValue   = $value[$fieldName];
                    $coercedField = self::coerceValue(
                        $fieldValue,
                        $field->getType(),
                        $blameNode,
                        self::atPath($path, $fieldName)
                    );
                    if ($coercedField['errors']) {
                        $errors = self::add($errors, $coercedField['errors']);
                    } else {
                        $coercedValue[$fieldName] = $coercedField['value'];
                    }
                } elseif ($field->defaultValueExists()) {
                    $coercedValue[$fieldName] = $field->defaultValue;
                } elseif ($field->getType() instanceof NonNull) {
                    $fieldPath = self::printPath(self::atPath($path, $fieldName));
                    $errors    = self::add(
                        $errors,
                        self::coercionError(
                            sprintf(
                                'Field %s of required type %s was not provided',
                                $fieldPath,
                                $field->type->toString()
                            ),
                            $blameNode
                        )
                    );
                }
            }

            // Ensure every provided field is defined.
            foreach ($value as $fieldName => $field) {
                if (array_key_exists($fieldName, $fields)) {
                    continue;
                }

                $suggestions = Utils::suggestionList(
                    $fieldName,
                    array_keys($fields)
                );
                $didYouMean  = $suggestions
                    ? 'did you mean ' . Utils::orList($suggestions) . '?'
                    : null;
                $errors      = self::add(
                    $errors,
                    self::coercionError(
                        sprintf('Field "%s" is not defined by type %s', $fieldName, $type->name),
                        $blameNode,
                        $path,
                        $didYouMean
                    )
                );
            }

            return $errors ? self::ofErrors($errors) : self::ofValue($coercedValue);
        }

        throw new Error(sprintf('Unexpected type %s', $type->name));
    }
Given a type and any value, return a runtime value coerced to match the type.

@param mixed[] $path