private function createContructor(array $visiblePropertyMap, array $hiddenPropertyMap) : string
    {
        $content = [];

        // Create a set of closures that will be called to hydrate the object.
        // Array of closures in a naturally indexed array, ordered, which will
        // then be called in order in the hydrate() and extract() methods.
        foreach ($hiddenPropertyMap as $className => $propertyNames) {
            // Hydrate closures
            $content[] = "\$this->hydrateCallbacks[] = \\Closure::bind(function (\$object, \$values) {";
            foreach ($propertyNames as $propertyName) {
                $content[] = "    if (isset(\$values['" . $propertyName . "']) || \$object->" . $propertyName . " !== null && \\array_key_exists('" . $propertyName . "', \$values)) {";
                $content[] = "        \$object->" . $propertyName . " = \$values['" . $propertyName . "'];";
                $content[] = "    }";
            }
            $content[] = '}, null, ' . \var_export($className, true) . ');' . "\n";

            // Extract closures
            $content[] = "\$this->extractCallbacks[] = \\Closure::bind(function (\$object, &\$values) {";
            foreach ($propertyNames as $propertyName) {
                $content[] = "    \$values['" . $propertyName . "'] = \$object->" . $propertyName . ";";
            }
            $content[] = '}, null, ' . \var_export($className, true) . ');' . "\n";
        }

        return \implode("\n", \array_map(
            function ($line) {
                return "        " . $line;
            }, $content
        ));
    }