src/Utils/AST.php
public static function astFromValue($value, InputType $type)
    {
        if ($type instanceof NonNull) {
            $astValue = self::astFromValue($value, $type->getWrappedType());
            if ($astValue instanceof NullValueNode) {
                return null;
            }

            return $astValue;
        }

        if ($value === null) {
            return new NullValueNode([]);
        }

        // Convert PHP array to GraphQL list. If the GraphQLType is a list, but
        // the value is not an array, convert the value using the list's item type.
        if ($type instanceof ListOfType) {
            $itemType = $type->getWrappedType();
            if (is_array($value) || ($value instanceof Traversable)) {
                $valuesNodes = [];
                foreach ($value as $item) {
                    $itemNode = self::astFromValue($item, $itemType);
                    if (! $itemNode) {
                        continue;
                    }

                    $valuesNodes[] = $itemNode;
                }

                return new ListValueNode(['values' => $valuesNodes]);
            }

            return self::astFromValue($value, $itemType);
        }

        // Populate the fields of the input object by creating ASTs from each value
        // in the PHP object according to the fields in the input type.
        if ($type instanceof InputObjectType) {
            $isArray     = is_array($value);
            $isArrayLike = $isArray || $value instanceof ArrayAccess;
            if ($value === null || (! $isArrayLike && ! is_object($value))) {
                return null;
            }
            $fields     = $type->getFields();
            $fieldNodes = [];
            foreach ($fields as $fieldName => $field) {
                if ($isArrayLike) {
                    $fieldValue = $value[$fieldName] ?? null;
                } else {
                    $fieldValue = $value->{$fieldName} ?? null;
                }

                // Have to check additionally if key exists, since we differentiate between
                // "no key" and "value is null":
                if ($fieldValue !== null) {
                    $fieldExists = true;
                } elseif ($isArray) {
                    $fieldExists = array_key_exists($fieldName, $value);
                } elseif ($isArrayLike) {
                    /** @var ArrayAccess $value */
                    $fieldExists = $value->offsetExists($fieldName);
                } else {
                    $fieldExists = property_exists($value, $fieldName);
                }

                if (! $fieldExists) {
                    continue;
                }

                $fieldNode = self::astFromValue($fieldValue, $field->getType());

                if (! $fieldNode) {
                    continue;
                }

                $fieldNodes[] = new ObjectFieldNode([
                    'name'  => new NameNode(['value' => $fieldName]),
                    'value' => $fieldNode,
                ]);
            }

            return new ObjectValueNode(['fields' => $fieldNodes]);
        }

        if ($type instanceof ScalarType || $type instanceof EnumType) {
            // Since value is an internally represented value, it must be serialized
            // to an externally represented value before converting into an AST.
            try {
                $serialized = $type->serialize($value);
            } catch (Exception $error) {
                if ($error instanceof Error && $type instanceof EnumType) {
                    return null;
                }
                throw $error;
            } catch (Throwable $error) {
                if ($error instanceof Error && $type instanceof EnumType) {
                    return null;
                }
                throw $error;
            }

            // Others serialize based on their corresponding PHP scalar types.
            if (is_bool($serialized)) {
                return new BooleanValueNode(['value' => $serialized]);
            }
            if (is_int($serialized)) {
                return new IntValueNode(['value' => $serialized]);
            }
            if (is_float($serialized)) {
                // int cast with == used for performance reasons
                // phpcs:ignore
                if ((int) $serialized == $serialized) {
                    return new IntValueNode(['value' => $serialized]);
                }

                return new FloatValueNode(['value' => $serialized]);
            }
            if (is_string($serialized)) {
                // Enum types use Enum literals.
                if ($type instanceof EnumType) {
                    return new EnumValueNode(['value' => $serialized]);
                }

                // ID types can use Int literals.
                $asInt = (int) $serialized;
                if ($type instanceof IDType && (string) $asInt === $serialized) {
                    return new IntValueNode(['value' => $serialized]);
                }

                // Use json_encode, which uses the same string encoding as GraphQL,
                // then remove the quotes.
                return new StringValueNode(['value' => $serialized]);
            }

            throw new InvariantViolation('Cannot convert value to AST: ' . Utils::printSafe($serialized));
        }

        throw new Error('Unknown type: ' . Utils::printSafe($type) . '.');
    }
public static function astFromValue($value, InputType $type)
    {
        if ($type instanceof NonNull) {
            $astValue = self::astFromValue($value, $type->getWrappedType());
            if ($astValue instanceof NullValueNode) {
                return null;
            }

            return $astValue;
        }

        if ($value === null) {
            return new NullValueNode([]);
        }

        // Convert PHP array to GraphQL list. If the GraphQLType is a list, but
        // the value is not an array, convert the value using the list's item type.
        if ($type instanceof ListOfType) {
            $itemType = $type->getWrappedType();
            if (is_array($value) || ($value instanceof Traversable)) {
                $valuesNodes = [];
                foreach ($value as $item) {
                    $itemNode = self::astFromValue($item, $itemType);
                    if (! $itemNode) {
                        continue;
                    }

                    $valuesNodes[] = $itemNode;
                }

                return new ListValueNode(['values' => $valuesNodes]);
            }

            return self::astFromValue($value, $itemType);
        }

        // Populate the fields of the input object by creating ASTs from each value
        // in the PHP object according to the fields in the input type.
        if ($type instanceof InputObjectType) {
            $isArray     = is_array($value);
            $isArrayLike = $isArray || $value instanceof ArrayAccess;
            if ($value === null || (! $isArrayLike && ! is_object($value))) {
                return null;
            }
            $fields     = $type->getFields();
            $fieldNodes = [];
            foreach ($fields as $fieldName => $field) {
                if ($isArrayLike) {
                    $fieldValue = $value[$fieldName] ?? null;
                } else {
                    $fieldValue = $value->{$fieldName} ?? null;
                }

                // Have to check additionally if key exists, since we differentiate between
                // "no key" and "value is null":
                if ($fieldValue !== null) {
                    $fieldExists = true;
                } elseif ($isArray) {
                    $fieldExists = array_key_exists($fieldName, $value);
                } elseif ($isArrayLike) {
                    /** @var ArrayAccess $value */
                    $fieldExists = $value->offsetExists($fieldName);
                } else {
                    $fieldExists = property_exists($value, $fieldName);
                }

                if (! $fieldExists) {
                    continue;
                }

                $fieldNode = self::astFromValue($fieldValue, $field->getType());

                if (! $fieldNode) {
                    continue;
                }

                $fieldNodes[] = new ObjectFieldNode([
                    'name'  => new NameNode(['value' => $fieldName]),
                    'value' => $fieldNode,
                ]);
            }

            return new ObjectValueNode(['fields' => $fieldNodes]);
        }

        if ($type instanceof ScalarType || $type instanceof EnumType) {
            // Since value is an internally represented value, it must be serialized
            // to an externally represented value before converting into an AST.
            try {
                $serialized = $type->serialize($value);
            } catch (Exception $error) {
                if ($error instanceof Error && $type instanceof EnumType) {
                    return null;
                }
                throw $error;
            } catch (Throwable $error) {
                if ($error instanceof Error && $type instanceof EnumType) {
                    return null;
                }
                throw $error;
            }

            // Others serialize based on their corresponding PHP scalar types.
            if (is_bool($serialized)) {
                return new BooleanValueNode(['value' => $serialized]);
            }
            if (is_int($serialized)) {
                return new IntValueNode(['value' => $serialized]);
            }
            if (is_float($serialized)) {
                // int cast with == used for performance reasons
                // phpcs:ignore
                if ((int) $serialized == $serialized) {
                    return new IntValueNode(['value' => $serialized]);
                }

                return new FloatValueNode(['value' => $serialized]);
            }
            if (is_string($serialized)) {
                // Enum types use Enum literals.
                if ($type instanceof EnumType) {
                    return new EnumValueNode(['value' => $serialized]);
                }

                // ID types can use Int literals.
                $asInt = (int) $serialized;
                if ($type instanceof IDType && (string) $asInt === $serialized) {
                    return new IntValueNode(['value' => $serialized]);
                }

                // Use json_encode, which uses the same string encoding as GraphQL,
                // then remove the quotes.
                return new StringValueNode(['value' => $serialized]);
            }

            throw new InvariantViolation('Cannot convert value to AST: ' . Utils::printSafe($serialized));
        }

        throw new Error('Unknown type: ' . Utils::printSafe($type) . '.');
    }
Produces a GraphQL Value AST given a PHP value.

Optionally, a GraphQL type may be provided, which will be used to
disambiguate between value primitives.

| PHP Value     | GraphQL Value        |
| ------------- | -------------------- |
| Object        | Input Object         |
| Assoc Array   | Input Object         |
| Array         | List                 |
| Boolean       | Boolean              |
| String        | String / Enum Value  |
| Int           | Int                  |
| Float         | Int / Float          |
| Mixed         | Enum Value           |
| null          | NullValue            |

@param Type|mixed|null $value

@return ObjectValueNode|ListValueNode|BooleanValueNode|IntValueNode|FloatValueNode|EnumValueNode|StringValueNode|NullValueNode

@api