public function encode($data, $schema = null)
    {
        if (null !== $schema) {
            $errors = $this->validator->validate($data, $schema);

            if (count($errors) > 0) {
                throw ValidationFailedException::fromErrors($errors);
            }
        }

        $options = 0;

        if (self::JSON_OBJECT === $this->arrayEncoding) {
            $options |= JSON_FORCE_OBJECT;
        }

        if (self::JSON_NUMBER === $this->numericEncoding) {
            $options |= JSON_NUMERIC_CHECK;
        }

        if ($this->gtLtEscaped) {
            $options |= JSON_HEX_TAG;
        }

        if ($this->ampersandEscaped) {
            $options |= JSON_HEX_AMP;
        }

        if ($this->singleQuoteEscaped) {
            $options |= JSON_HEX_APOS;
        }

        if ($this->doubleQuoteEscaped) {
            $options |= JSON_HEX_QUOT;
        }

        if (PHP_VERSION_ID >= 50400) {
            if (!$this->slashEscaped) {
                $options |= JSON_UNESCAPED_SLASHES;
            }

            if (!$this->unicodeEscaped) {
                $options |= JSON_UNESCAPED_UNICODE;
            }

            if ($this->prettyPrinting) {
                $options |= JSON_PRETTY_PRINT;
            }
        }

        if (PHP_VERSION_ID < 71000) {
            // PHP before 7.1 decodes empty properties as "_empty_". Make
            // sure the encoding of these properties works again.
            if (is_object($data) && isset($data->{'_empty_'})) {
                $data = (array) $data;
            }

            if (is_array($data) && isset($data['_empty_'])) {
                // Maintain key order
                $keys = array_keys($data);
                $keys[array_search('_empty_', $keys, true)] = '';
                $data = array_combine($keys, $data);
            }
        }

        if (PHP_VERSION_ID >= 50500) {
            $maxDepth = $this->maxDepth;

            // We subtract 1 from the max depth to make JsonDecoder and
            // JsonEncoder consistent. json_encode() and json_decode() behave
            // differently for their depth values. See the test cases for
            // examples.
            // HHVM does not have this inconsistency.
            if (!defined('HHVM_VERSION')) {
                --$maxDepth;
            }

            $encoded = json_encode($data, $options, $maxDepth);
        } else {
            $encoded = json_encode($data, $options);
        }

        if (PHP_VERSION_ID < 50400 && !$this->slashEscaped) {
            // PHP below 5.4 does not allow to turn off slash escaping. Let's
            // unescape slashes manually.
            $encoded = str_replace('\\/', '/', $encoded);
        }

        if (JSON_ERROR_NONE !== json_last_error()) {
            throw new EncodingFailedException(sprintf(
                'The data could not be encoded as JSON: %s',
                JsonError::getLastErrorMessage()
            ), json_last_error());
        }

        if ($this->terminatedWithLineFeed) {
            $encoded .= "\n";
        }

        return $encoded;
    }